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
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.
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
45 void JSD_ASSERT_VALID_VALUE(JSDValue
* 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
));
57 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROTO
));
58 JS_ASSERT(jsdval
->proto
->nref
> 0);
62 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PARENT
));
63 JS_ASSERT(jsdval
->parent
->nref
> 0);
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
)
75 JS_ASSERT(jsdprop
->name
);
76 JS_ASSERT(jsdprop
->name
->nref
> 0);
77 JS_ASSERT(jsdprop
->val
);
78 JS_ASSERT(jsdprop
->val
->nref
> 0);
80 JS_ASSERT(jsdprop
->alias
->nref
> 0);
86 jsd_IsValueObject(JSDContext
* jsdc
, JSDValue
* jsdval
)
88 return JSVAL_IS_OBJECT(jsdval
->val
);
92 jsd_IsValueNumber(JSDContext
* jsdc
, JSDValue
* jsdval
)
94 return JSVAL_IS_NUMBER(jsdval
->val
);
98 jsd_IsValueInt(JSDContext
* jsdc
, JSDValue
* jsdval
)
100 return JSVAL_IS_INT(jsdval
->val
);
104 jsd_IsValueDouble(JSDContext
* jsdc
, JSDValue
* jsdval
)
106 return JSVAL_IS_DOUBLE(jsdval
->val
);
110 jsd_IsValueString(JSDContext
* jsdc
, JSDValue
* jsdval
)
112 return JSVAL_IS_STRING(jsdval
->val
);
116 jsd_IsValueBoolean(JSDContext
* jsdc
, JSDValue
* jsdval
)
118 return JSVAL_IS_BOOLEAN(jsdval
->val
);
122 jsd_IsValueNull(JSDContext
* jsdc
, JSDValue
* jsdval
)
124 return JSVAL_IS_NULL(jsdval
->val
);
128 jsd_IsValueVoid(JSDContext
* jsdc
, JSDValue
* jsdval
)
130 return JSVAL_IS_VOID(jsdval
->val
);
134 jsd_IsValuePrimitive(JSDContext
* jsdc
, JSDValue
* jsdval
)
136 return JSVAL_IS_PRIMITIVE(jsdval
->val
);
140 jsd_IsValueFunction(JSDContext
* jsdc
, JSDValue
* jsdval
)
142 return !JSVAL_IS_PRIMITIVE(jsdval
->val
) &&
143 JS_ObjectIsFunction(jsdc
->dumbContext
, JSVAL_TO_OBJECT(jsdval
->val
));
147 jsd_IsValueNative(JSDContext
* jsdc
, JSDValue
* jsdval
)
149 JSContext
* cx
= jsdc
->dumbContext
;
150 jsval val
= jsdval
->val
;
152 JSExceptionState
* exceptionState
;
154 if(jsd_IsValueFunction(jsdc
, jsdval
))
156 JSBool ok
= JS_FALSE
;
158 exceptionState
= JS_SaveExceptionState(cx
);
159 fun
= JS_ValueToFunction(cx
, val
);
160 JS_RestoreExceptionState(cx
, exceptionState
);
162 ok
= JS_GetFunctionScript(cx
, fun
) ? JS_FALSE
: JS_TRUE
;
167 return !JSVAL_IS_PRIMITIVE(val
);
170 /***************************************************************************/
173 jsd_GetValueBoolean(JSDContext
* jsdc
, JSDValue
* jsdval
)
175 jsval val
= jsdval
->val
;
176 if(!JSVAL_IS_BOOLEAN(val
))
178 return JSVAL_TO_BOOLEAN(val
);
182 jsd_GetValueInt(JSDContext
* jsdc
, JSDValue
* jsdval
)
184 jsval val
= jsdval
->val
;
185 if(!JSVAL_IS_INT(val
))
187 return JSVAL_TO_INT(val
);
191 jsd_GetValueDouble(JSDContext
* jsdc
, JSDValue
* jsdval
)
193 jsval val
= jsdval
->val
;
194 if(!JSVAL_IS_DOUBLE(val
))
196 return JSVAL_TO_DOUBLE(val
);
200 jsd_GetValueString(JSDContext
* jsdc
, JSDValue
* jsdval
)
202 JSContext
* cx
= jsdc
->dumbContext
;
203 JSExceptionState
* exceptionState
;
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
);
213 exceptionState
= JS_SaveExceptionState(cx
);
214 jsdval
->string
= JS_ValueToString(cx
, jsdval
->val
);
215 JS_RestoreExceptionState(cx
, exceptionState
);
218 if(!JS_AddNamedRoot(cx
, &jsdval
->string
, "ValueString"))
219 jsdval
->string
= NULL
;
224 return jsdval
->string
;
228 jsd_GetValueFunctionName(JSDContext
* jsdc
, JSDValue
* jsdval
)
230 JSContext
* cx
= jsdc
->dumbContext
;
232 JSExceptionState
* exceptionState
;
234 if(!jsdval
->funName
&& jsd_IsValueFunction(jsdc
, jsdval
))
237 exceptionState
= JS_SaveExceptionState(cx
);
238 fun
= JS_ValueToFunction(cx
, jsdval
->val
);
239 JS_RestoreExceptionState(cx
, exceptionState
);
243 jsdval
->funName
= JS_GetFunctionName(fun
);
245 return jsdval
->funName
;
248 /***************************************************************************/
251 jsd_NewValue(JSDContext
* jsdc
, jsval val
)
255 if(!(jsdval
= (JSDValue
*) calloc(1, sizeof(JSDValue
))))
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
);
272 JS_INIT_CLIST(&jsdval
->props
);
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
);
295 jsd_GetValueWrappedJSVal(JSDContext
* jsdc
, JSDValue
* jsdval
)
300 static JSDProperty
* _newProperty(JSDContext
* jsdc
, JSPropertyDesc
* pd
,
301 uintN additionalFlags
)
303 JSDProperty
* jsdprop
;
305 if(!(jsdprop
= (JSDProperty
*) calloc(1, sizeof(JSDProperty
))))
308 JS_INIT_CLIST(&jsdprop
->links
);
310 jsdprop
->flags
= pd
->flags
| additionalFlags
;
311 jsdprop
->slot
= pd
->slot
;
313 if(!(jsdprop
->name
= jsd_NewValue(jsdc
, pd
->id
)))
316 if(!(jsdprop
->val
= jsd_NewValue(jsdc
, pd
->value
)))
319 if((jsdprop
->flags
& JSDPD_ALIAS
) &&
320 !(jsdprop
->alias
= jsd_NewValue(jsdc
, pd
->alias
)))
325 jsd_DropProperty(jsdc
, jsdprop
);
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
;
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
))
357 if(!JS_GetPropertyDescArray(cx
, JSVAL_TO_OBJECT(jsdval
->val
), &pda
))
363 for(i
= 0; i
< pda
.length
; i
++)
365 JSDProperty
* prop
= _newProperty(jsdc
, &pda
.array
[i
], 0);
368 _freeProps(jsdc
, jsdval
);
371 JS_APPEND_LINK(&prop
->links
, &jsdval
->props
);
373 JS_PutPropertyDescArray(cx
, &pda
);
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;}
383 jsd_RefreshValue(JSDContext
* jsdc
, JSDValue
* jsdval
)
385 JSContext
* cx
= jsdc
->dumbContext
;
389 /* if the jsval is a string, then we didn't need to root the string */
390 if(!JSVAL_IS_STRING(jsdval
->val
))
393 JS_RemoveRoot(cx
, &jsdval
->string
);
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
);
408 /***************************************************************************/
411 jsd_GetCountOfProperties(JSDContext
* jsdc
, JSDValue
* jsdval
)
413 JSDProperty
* jsdprop
;
416 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
)))
417 if(!_buildProps(jsdc
, jsdval
))
420 for(jsdprop
= (JSDProperty
*)jsdval
->props
.next
;
421 jsdprop
!= (JSDProperty
*)&jsdval
->props
;
422 jsdprop
= (JSDProperty
*)jsdprop
->links
.next
)
430 jsd_IterateProperties(JSDContext
* jsdc
, JSDValue
* jsdval
, JSDProperty
**iterp
)
432 JSDProperty
* jsdprop
= *iterp
;
433 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
)))
436 if(!_buildProps(jsdc
, jsdval
))
441 jsdprop
= (JSDProperty
*)jsdval
->props
.next
;
442 if(jsdprop
== (JSDProperty
*)&jsdval
->props
)
444 *iterp
= (JSDProperty
*)jsdprop
->links
.next
;
452 jsd_GetValueProperty(JSDContext
* jsdc
, JSDValue
* jsdval
, JSString
* name
)
454 JSContext
* cx
= jsdc
->dumbContext
;
455 JSDProperty
* jsdprop
;
456 JSDProperty
* iter
= NULL
;
461 const jschar
* nameChars
;
465 if(!jsd_IsValueObject(jsdc
, jsdval
))
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
))
474 JSD_DropProperty(jsdc
, jsdprop
);
476 /* Not found in property list, look it up explicitly */
478 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
481 nameChars
= JS_GetStringChars(name
);
482 nameLen
= JS_GetStringLength(name
);
486 JS_GetUCPropertyAttributes(cx
, obj
, nameChars
, nameLen
, &attrs
, &found
);
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
))
504 pd
.flags
= JSPD_EXCEPTION
;
508 pd
.flags
= JSPD_ERROR
;
509 pd
.value
= JSVAL_VOID
;
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
);
530 jsd_GetValuePrototype(JSDContext
* jsdc
, JSDValue
* jsdval
)
532 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROTO
)))
536 JS_ASSERT(!jsdval
->proto
);
537 SET_BIT_FLAG(jsdval
->flags
, GOT_PROTO
);
538 if(!JSVAL_IS_OBJECT(jsdval
->val
))
540 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
542 JS_BeginRequest(jsdc
->dumbContext
);
543 proto
= JS_GetPrototype(jsdc
->dumbContext
, obj
);
544 JS_EndRequest(jsdc
->dumbContext
);
547 jsdval
->proto
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(proto
));
550 jsdval
->proto
->nref
++;
551 return jsdval
->proto
;
555 jsd_GetValueParent(JSDContext
* jsdc
, JSDValue
* jsdval
)
557 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PARENT
)))
561 JS_ASSERT(!jsdval
->parent
);
562 SET_BIT_FLAG(jsdval
->flags
, GOT_PARENT
);
563 if(!JSVAL_IS_OBJECT(jsdval
->val
))
565 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
567 JS_BeginRequest(jsdc
->dumbContext
);
568 parent
= JS_GetParent(jsdc
->dumbContext
,obj
);
569 JS_EndRequest(jsdc
->dumbContext
);
572 jsdval
->parent
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(parent
));
575 jsdval
->parent
->nref
++;
576 return jsdval
->parent
;
580 jsd_GetValueConstructor(JSDContext
* jsdc
, JSDValue
* jsdval
)
582 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_CTOR
)))
587 JS_ASSERT(!jsdval
->ctor
);
588 SET_BIT_FLAG(jsdval
->flags
, GOT_CTOR
);
589 if(!JSVAL_IS_OBJECT(jsdval
->val
))
591 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
593 JS_BeginRequest(jsdc
->dumbContext
);
594 proto
= JS_GetPrototype(jsdc
->dumbContext
,obj
);
597 JS_EndRequest(jsdc
->dumbContext
);
600 ctor
= JS_GetConstructor(jsdc
->dumbContext
,proto
);
601 JS_EndRequest(jsdc
->dumbContext
);
604 jsdval
->ctor
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(ctor
));
607 jsdval
->ctor
->nref
++;
612 jsd_GetValueClassName(JSDContext
* jsdc
, JSDValue
* jsdval
)
614 jsval val
= jsdval
->val
;
615 if(!jsdval
->className
&& JSVAL_IS_OBJECT(val
))
618 if(!(obj
= JSVAL_TO_OBJECT(val
)))
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 /***************************************************************************/
632 jsd_GetPropertyName(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
634 jsdprop
->name
->nref
++;
635 return jsdprop
->name
;
639 jsd_GetPropertyValue(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
641 jsdprop
->val
->nref
++;
646 jsd_GetPropertyAlias(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
649 jsdprop
->alias
->nref
++;
650 return jsdprop
->alias
;
654 jsd_GetPropertyFlags(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
656 return jsdprop
->flags
;
660 jsd_GetPropertyVarArgSlot(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
662 return jsdprop
->slot
;
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
);