Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / js / jsd / jsd_val.c
blob1619de63c15bdfaa7182755d33aab68d6590ae7d
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * JavaScript Debugging support - Value and Property support
42 #include "jsd.h"
44 #ifdef DEBUG
45 void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
47 JS_ASSERT(jsdval);
48 JS_ASSERT(jsdval->nref > 0);
49 if(!JS_CLIST_IS_EMPTY(&jsdval->props))
51 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
52 JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));
55 if(jsdval->proto)
57 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
58 JS_ASSERT(jsdval->proto->nref > 0);
60 if(jsdval->parent)
62 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
63 JS_ASSERT(jsdval->parent->nref > 0);
65 if(jsdval->ctor)
67 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR));
68 JS_ASSERT(jsdval->ctor->nref > 0);
72 void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop)
74 JS_ASSERT(jsdprop);
75 JS_ASSERT(jsdprop->name);
76 JS_ASSERT(jsdprop->name->nref > 0);
77 JS_ASSERT(jsdprop->val);
78 JS_ASSERT(jsdprop->val->nref > 0);
79 if(jsdprop->alias)
80 JS_ASSERT(jsdprop->alias->nref > 0);
82 #endif
85 JSBool
86 jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
88 return JSVAL_IS_OBJECT(jsdval->val);
91 JSBool
92 jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
94 return JSVAL_IS_NUMBER(jsdval->val);
97 JSBool
98 jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
100 return JSVAL_IS_INT(jsdval->val);
103 JSBool
104 jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
106 return JSVAL_IS_DOUBLE(jsdval->val);
109 JSBool
110 jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
112 return JSVAL_IS_STRING(jsdval->val);
115 JSBool
116 jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
118 return JSVAL_IS_BOOLEAN(jsdval->val);
121 JSBool
122 jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
124 return JSVAL_IS_NULL(jsdval->val);
127 JSBool
128 jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
130 return JSVAL_IS_VOID(jsdval->val);
133 JSBool
134 jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
136 return JSVAL_IS_PRIMITIVE(jsdval->val);
139 JSBool
140 jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
142 return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
143 JS_ObjectIsFunction(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
146 JSBool
147 jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
149 JSContext* cx = jsdc->dumbContext;
150 jsval val = jsdval->val;
151 JSFunction* fun;
152 JSExceptionState* exceptionState;
154 if(jsd_IsValueFunction(jsdc, jsdval))
156 JSBool ok = JS_FALSE;
157 JS_BeginRequest(cx);
158 exceptionState = JS_SaveExceptionState(cx);
159 fun = JS_ValueToFunction(cx, val);
160 JS_RestoreExceptionState(cx, exceptionState);
161 if(fun)
162 ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
163 JS_EndRequest(cx);
164 JS_ASSERT(fun);
165 return ok;
167 return !JSVAL_IS_PRIMITIVE(val);
170 /***************************************************************************/
172 JSBool
173 jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
175 jsval val = jsdval->val;
176 if(!JSVAL_IS_BOOLEAN(val))
177 return JS_FALSE;
178 return JSVAL_TO_BOOLEAN(val);
181 int32
182 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
184 jsval val = jsdval->val;
185 if(!JSVAL_IS_INT(val))
186 return 0;
187 return JSVAL_TO_INT(val);
190 jsdouble*
191 jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
193 jsval val = jsdval->val;
194 if(!JSVAL_IS_DOUBLE(val))
195 return 0;
196 return JSVAL_TO_DOUBLE(val);
199 JSString*
200 jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
202 JSContext* cx = jsdc->dumbContext;
203 JSExceptionState* exceptionState;
205 if(!jsdval->string)
207 /* if the jsval is a string, then we don't need to double root it */
208 if(JSVAL_IS_STRING(jsdval->val))
209 jsdval->string = JSVAL_TO_STRING(jsdval->val);
210 else
212 JS_BeginRequest(cx);
213 exceptionState = JS_SaveExceptionState(cx);
214 jsdval->string = JS_ValueToString(cx, jsdval->val);
215 JS_RestoreExceptionState(cx, exceptionState);
216 if(jsdval->string)
218 if(!JS_AddNamedRoot(cx, &jsdval->string, "ValueString"))
219 jsdval->string = NULL;
221 JS_EndRequest(cx);
224 return jsdval->string;
227 const char*
228 jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
230 JSContext* cx = jsdc->dumbContext;
231 JSFunction* fun;
232 JSExceptionState* exceptionState;
234 if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
236 JS_BeginRequest(cx);
237 exceptionState = JS_SaveExceptionState(cx);
238 fun = JS_ValueToFunction(cx, jsdval->val);
239 JS_RestoreExceptionState(cx, exceptionState);
240 JS_EndRequest(cx);
241 if(!fun)
242 return NULL;
243 jsdval->funName = JS_GetFunctionName(fun);
245 return jsdval->funName;
248 /***************************************************************************/
250 JSDValue*
251 jsd_NewValue(JSDContext* jsdc, jsval val)
253 JSDValue* jsdval;
255 if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
256 return NULL;
258 if(JSVAL_IS_GCTHING(val))
260 JSBool ok = JS_FALSE;
261 JS_BeginRequest(jsdc->dumbContext);
262 ok = JS_AddNamedRoot(jsdc->dumbContext, &jsdval->val, "JSDValue");
263 JS_EndRequest(jsdc->dumbContext);
264 if(!ok)
266 free(jsdval);
267 return NULL;
270 jsdval->val = val;
271 jsdval->nref = 1;
272 JS_INIT_CLIST(&jsdval->props);
274 return jsdval;
277 void
278 jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
280 JS_ASSERT(jsdval->nref > 0);
281 if(0 == --jsdval->nref)
283 jsd_RefreshValue(jsdc, jsdval);
284 if(JSVAL_IS_GCTHING(jsdval->val))
286 JS_BeginRequest(jsdc->dumbContext);
287 JS_RemoveRoot(jsdc->dumbContext, &jsdval->val);
288 JS_EndRequest(jsdc->dumbContext);
290 free(jsdval);
294 jsval
295 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
297 return jsdval->val;
300 static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
301 uintN additionalFlags)
303 JSDProperty* jsdprop;
305 if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
306 return NULL;
308 JS_INIT_CLIST(&jsdprop->links);
309 jsdprop->nref = 1;
310 jsdprop->flags = pd->flags | additionalFlags;
311 jsdprop->slot = pd->slot;
313 if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
314 goto new_prop_fail;
316 if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
317 goto new_prop_fail;
319 if((jsdprop->flags & JSDPD_ALIAS) &&
320 !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
321 goto new_prop_fail;
323 return jsdprop;
324 new_prop_fail:
325 jsd_DropProperty(jsdc, jsdprop);
326 return NULL;
329 static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
331 JSDProperty* jsdprop;
333 while(jsdprop = (JSDProperty*)jsdval->props.next,
334 jsdprop != (JSDProperty*)&jsdval->props)
336 JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
337 jsd_DropProperty(jsdc, jsdprop);
339 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
340 CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
343 static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
345 JSContext* cx = jsdc->dumbContext;
346 JSPropertyDescArray pda;
347 uintN i;
349 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
350 JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
351 JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));
353 if(!JSVAL_IS_OBJECT(jsdval->val) || JSVAL_IS_NULL(jsdval->val))
354 return JS_FALSE;
356 JS_BeginRequest(cx);
357 if(!JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(jsdval->val), &pda))
359 JS_EndRequest(cx);
360 return JS_FALSE;
363 for(i = 0; i < pda.length; i++)
365 JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
366 if(!prop)
368 _freeProps(jsdc, jsdval);
369 break;
371 JS_APPEND_LINK(&prop->links, &jsdval->props);
373 JS_PutPropertyDescArray(cx, &pda);
374 JS_EndRequest(cx);
375 SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
376 return !JS_CLIST_IS_EMPTY(&jsdval->props);
379 #undef DROP_CLEAR_VALUE
380 #define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;}
382 void
383 jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
385 JSContext* cx = jsdc->dumbContext;
387 if(jsdval->string)
389 /* if the jsval is a string, then we didn't need to root the string */
390 if(!JSVAL_IS_STRING(jsdval->val))
392 JS_BeginRequest(cx);
393 JS_RemoveRoot(cx, &jsdval->string);
394 JS_EndRequest(cx);
396 jsdval->string = NULL;
399 jsdval->funName = NULL;
400 jsdval->className = NULL;
401 DROP_CLEAR_VALUE(jsdc, jsdval->proto);
402 DROP_CLEAR_VALUE(jsdc, jsdval->parent);
403 DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
404 _freeProps(jsdc, jsdval);
405 jsdval->flags = 0;
408 /***************************************************************************/
410 uintN
411 jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
413 JSDProperty* jsdprop;
414 uintN count = 0;
416 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
417 if(!_buildProps(jsdc, jsdval))
418 return 0;
420 for(jsdprop = (JSDProperty*)jsdval->props.next;
421 jsdprop != (JSDProperty*)&jsdval->props;
422 jsdprop = (JSDProperty*)jsdprop->links.next)
424 count++;
426 return count;
429 JSDProperty*
430 jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
432 JSDProperty* jsdprop = *iterp;
433 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
435 JS_ASSERT(!jsdprop);
436 if(!_buildProps(jsdc, jsdval))
437 return NULL;
440 if(!jsdprop)
441 jsdprop = (JSDProperty*)jsdval->props.next;
442 if(jsdprop == (JSDProperty*)&jsdval->props)
443 return NULL;
444 *iterp = (JSDProperty*)jsdprop->links.next;
446 JS_ASSERT(jsdprop);
447 jsdprop->nref++;
448 return jsdprop;
451 JSDProperty*
452 jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
454 JSContext* cx = jsdc->dumbContext;
455 JSDProperty* jsdprop;
456 JSDProperty* iter = NULL;
457 JSObject* obj;
458 uintN attrs = 0;
459 JSBool found;
460 JSPropertyDesc pd;
461 const jschar * nameChars;
462 size_t nameLen;
463 jsval val;
465 if(!jsd_IsValueObject(jsdc, jsdval))
466 return NULL;
468 /* If we already have the prop, then return it */
469 while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
471 JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
472 if(propName && !JS_CompareStrings(propName, name))
473 return jsdprop;
474 JSD_DropProperty(jsdc, jsdprop);
476 /* Not found in property list, look it up explicitly */
478 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
479 return NULL;
481 nameChars = JS_GetStringChars(name);
482 nameLen = JS_GetStringLength(name);
484 JS_BeginRequest(cx);
486 JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
487 if (!found)
489 JS_EndRequest(cx);
490 return NULL;
493 JS_ClearPendingException(cx);
495 if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
497 if (JS_IsExceptionPending(cx))
499 if (!JS_GetPendingException(cx, &pd.value))
501 JS_EndRequest(cx);
502 return NULL;
504 pd.flags = JSPD_EXCEPTION;
506 else
508 pd.flags = JSPD_ERROR;
509 pd.value = JSVAL_VOID;
512 else
514 pd.value = val;
517 JS_EndRequest(cx);
519 pd.id = STRING_TO_JSVAL(name);
520 pd.alias = pd.slot = pd.spare = 0;
521 pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
522 | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0
523 | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
525 return _newProperty(jsdc, &pd, JSDPD_HINTED);
529 JSDValue*
530 jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
532 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
534 JSObject* obj;
535 JSObject* proto;
536 JS_ASSERT(!jsdval->proto);
537 SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
538 if(!JSVAL_IS_OBJECT(jsdval->val))
539 return NULL;
540 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
541 return NULL;
542 JS_BeginRequest(jsdc->dumbContext);
543 proto = JS_GetPrototype(jsdc->dumbContext, obj);
544 JS_EndRequest(jsdc->dumbContext);
545 if(!proto)
546 return NULL;
547 jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
549 if(jsdval->proto)
550 jsdval->proto->nref++;
551 return jsdval->proto;
554 JSDValue*
555 jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
557 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
559 JSObject* obj;
560 JSObject* parent;
561 JS_ASSERT(!jsdval->parent);
562 SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
563 if(!JSVAL_IS_OBJECT(jsdval->val))
564 return NULL;
565 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
566 return NULL;
567 JS_BeginRequest(jsdc->dumbContext);
568 parent = JS_GetParent(jsdc->dumbContext,obj);
569 JS_EndRequest(jsdc->dumbContext);
570 if(!parent)
571 return NULL;
572 jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
574 if(jsdval->parent)
575 jsdval->parent->nref++;
576 return jsdval->parent;
579 JSDValue*
580 jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
582 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
584 JSObject* obj;
585 JSObject* proto;
586 JSObject* ctor;
587 JS_ASSERT(!jsdval->ctor);
588 SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
589 if(!JSVAL_IS_OBJECT(jsdval->val))
590 return NULL;
591 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
592 return NULL;
593 JS_BeginRequest(jsdc->dumbContext);
594 proto = JS_GetPrototype(jsdc->dumbContext,obj);
595 if(!proto)
597 JS_EndRequest(jsdc->dumbContext);
598 return NULL;
600 ctor = JS_GetConstructor(jsdc->dumbContext,proto);
601 JS_EndRequest(jsdc->dumbContext);
602 if(!ctor)
603 return NULL;
604 jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
606 if(jsdval->ctor)
607 jsdval->ctor->nref++;
608 return jsdval->ctor;
611 const char*
612 jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
614 jsval val = jsdval->val;
615 if(!jsdval->className && JSVAL_IS_OBJECT(val))
617 JSObject* obj;
618 if(!(obj = JSVAL_TO_OBJECT(val)))
619 return NULL;
620 JS_BeginRequest(jsdc->dumbContext);
621 if(JS_GET_CLASS(jsdc->dumbContext, obj))
622 jsdval->className = JS_GET_CLASS(jsdc->dumbContext, obj)->name;
623 JS_EndRequest(jsdc->dumbContext);
625 return jsdval->className;
628 /***************************************************************************/
629 /***************************************************************************/
631 JSDValue*
632 jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
634 jsdprop->name->nref++;
635 return jsdprop->name;
638 JSDValue*
639 jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
641 jsdprop->val->nref++;
642 return jsdprop->val;
645 JSDValue*
646 jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
648 if(jsdprop->alias)
649 jsdprop->alias->nref++;
650 return jsdprop->alias;
653 uintN
654 jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
656 return jsdprop->flags;
659 uintN
660 jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop)
662 return jsdprop->slot;
665 void
666 jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
668 JS_ASSERT(jsdprop->nref > 0);
669 if(0 == --jsdprop->nref)
671 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
672 DROP_CLEAR_VALUE(jsdc, jsdprop->val);
673 DROP_CLEAR_VALUE(jsdc, jsdprop->name);
674 DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
675 free(jsdprop);