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
47 * Lifted with slight modification from jsobj.h
50 #define OBJ_TO_OUTER_OBJECT(cx, obj) \
52 JSClass *clasp_ = JS_GetClass(cx, obj); \
53 if (clasp_->flags & JSCLASS_IS_EXTENDED) { \
54 JSExtendedClass *xclasp_ = (JSExtendedClass*) clasp_; \
55 if (xclasp_->outerObject) \
56 obj = xclasp_->outerObject(cx, obj); \
61 void JSD_ASSERT_VALID_VALUE(JSDValue
* jsdval
)
64 JS_ASSERT(jsdval
->nref
> 0);
65 if(!JS_CLIST_IS_EMPTY(&jsdval
->props
))
67 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
));
68 JS_ASSERT(JSVAL_IS_OBJECT(jsdval
->val
));
73 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROTO
));
74 JS_ASSERT(jsdval
->proto
->nref
> 0);
78 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PARENT
));
79 JS_ASSERT(jsdval
->parent
->nref
> 0);
83 JS_ASSERT(CHECK_BIT_FLAG(jsdval
->flags
, GOT_CTOR
));
84 JS_ASSERT(jsdval
->ctor
->nref
> 0);
88 void JSD_ASSERT_VALID_PROPERTY(JSDProperty
* jsdprop
)
91 JS_ASSERT(jsdprop
->name
);
92 JS_ASSERT(jsdprop
->name
->nref
> 0);
93 JS_ASSERT(jsdprop
->val
);
94 JS_ASSERT(jsdprop
->val
->nref
> 0);
96 JS_ASSERT(jsdprop
->alias
->nref
> 0);
102 jsd_IsValueObject(JSDContext
* jsdc
, JSDValue
* jsdval
)
104 return JSVAL_IS_OBJECT(jsdval
->val
);
108 jsd_IsValueNumber(JSDContext
* jsdc
, JSDValue
* jsdval
)
110 return JSVAL_IS_NUMBER(jsdval
->val
);
114 jsd_IsValueInt(JSDContext
* jsdc
, JSDValue
* jsdval
)
116 return JSVAL_IS_INT(jsdval
->val
);
120 jsd_IsValueDouble(JSDContext
* jsdc
, JSDValue
* jsdval
)
122 return JSVAL_IS_DOUBLE(jsdval
->val
);
126 jsd_IsValueString(JSDContext
* jsdc
, JSDValue
* jsdval
)
128 return JSVAL_IS_STRING(jsdval
->val
);
132 jsd_IsValueBoolean(JSDContext
* jsdc
, JSDValue
* jsdval
)
134 return JSVAL_IS_BOOLEAN(jsdval
->val
);
138 jsd_IsValueNull(JSDContext
* jsdc
, JSDValue
* jsdval
)
140 return JSVAL_IS_NULL(jsdval
->val
);
144 jsd_IsValueVoid(JSDContext
* jsdc
, JSDValue
* jsdval
)
146 return JSVAL_IS_VOID(jsdval
->val
);
150 jsd_IsValuePrimitive(JSDContext
* jsdc
, JSDValue
* jsdval
)
152 return JSVAL_IS_PRIMITIVE(jsdval
->val
);
156 jsd_IsValueFunction(JSDContext
* jsdc
, JSDValue
* jsdval
)
158 return !JSVAL_IS_PRIMITIVE(jsdval
->val
) &&
159 JS_ObjectIsFunction(jsdc
->dumbContext
, JSVAL_TO_OBJECT(jsdval
->val
));
163 jsd_IsValueNative(JSDContext
* jsdc
, JSDValue
* jsdval
)
165 JSContext
* cx
= jsdc
->dumbContext
;
166 jsval val
= jsdval
->val
;
168 JSExceptionState
* exceptionState
;
170 if(jsd_IsValueFunction(jsdc
, jsdval
))
172 JSBool ok
= JS_FALSE
;
174 exceptionState
= JS_SaveExceptionState(cx
);
175 fun
= JS_ValueToFunction(cx
, val
);
176 JS_RestoreExceptionState(cx
, exceptionState
);
178 ok
= JS_GetFunctionScript(cx
, fun
) ? JS_FALSE
: JS_TRUE
;
183 return !JSVAL_IS_PRIMITIVE(val
);
186 /***************************************************************************/
189 jsd_GetValueBoolean(JSDContext
* jsdc
, JSDValue
* jsdval
)
191 jsval val
= jsdval
->val
;
192 if(!JSVAL_IS_BOOLEAN(val
))
194 return JSVAL_TO_BOOLEAN(val
);
198 jsd_GetValueInt(JSDContext
* jsdc
, JSDValue
* jsdval
)
200 jsval val
= jsdval
->val
;
201 if(!JSVAL_IS_INT(val
))
203 return JSVAL_TO_INT(val
);
207 jsd_GetValueDouble(JSDContext
* jsdc
, JSDValue
* jsdval
)
209 jsval val
= jsdval
->val
;
210 if(!JSVAL_IS_DOUBLE(val
))
212 return JSVAL_TO_DOUBLE(val
);
216 jsd_GetValueString(JSDContext
* jsdc
, JSDValue
* jsdval
)
218 JSContext
* cx
= jsdc
->dumbContext
;
219 JSExceptionState
* exceptionState
;
223 /* if the jsval is a string, then we don't need to double root it */
224 if(JSVAL_IS_STRING(jsdval
->val
))
225 jsdval
->string
= JSVAL_TO_STRING(jsdval
->val
);
229 exceptionState
= JS_SaveExceptionState(cx
);
230 jsdval
->string
= JS_ValueToString(cx
, jsdval
->val
);
231 JS_RestoreExceptionState(cx
, exceptionState
);
234 if(!JS_AddNamedRoot(cx
, &jsdval
->string
, "ValueString"))
235 jsdval
->string
= NULL
;
240 return jsdval
->string
;
244 jsd_GetValueFunctionName(JSDContext
* jsdc
, JSDValue
* jsdval
)
246 JSContext
* cx
= jsdc
->dumbContext
;
248 JSExceptionState
* exceptionState
;
250 if(!jsdval
->funName
&& jsd_IsValueFunction(jsdc
, jsdval
))
253 exceptionState
= JS_SaveExceptionState(cx
);
254 fun
= JS_ValueToFunction(cx
, jsdval
->val
);
255 JS_RestoreExceptionState(cx
, exceptionState
);
259 jsdval
->funName
= JS_GetFunctionName(fun
);
261 return jsdval
->funName
;
264 /***************************************************************************/
267 jsd_NewValue(JSDContext
* jsdc
, jsval val
)
271 if(!(jsdval
= (JSDValue
*) calloc(1, sizeof(JSDValue
))))
274 if(JSVAL_IS_GCTHING(val
))
276 JSBool ok
= JS_FALSE
;
277 JS_BeginRequest(jsdc
->dumbContext
);
278 ok
= JS_AddNamedRoot(jsdc
->dumbContext
, &jsdval
->val
, "JSDValue");
279 JS_EndRequest(jsdc
->dumbContext
);
288 JS_INIT_CLIST(&jsdval
->props
);
294 jsd_DropValue(JSDContext
* jsdc
, JSDValue
* jsdval
)
296 JS_ASSERT(jsdval
->nref
> 0);
297 if(0 == --jsdval
->nref
)
299 jsd_RefreshValue(jsdc
, jsdval
);
300 if(JSVAL_IS_GCTHING(jsdval
->val
))
302 JS_BeginRequest(jsdc
->dumbContext
);
303 JS_RemoveRoot(jsdc
->dumbContext
, &jsdval
->val
);
304 JS_EndRequest(jsdc
->dumbContext
);
311 jsd_GetValueWrappedJSVal(JSDContext
* jsdc
, JSDValue
* jsdval
)
315 jsval val
= jsdval
->val
;
316 if (!JSVAL_IS_PRIMITIVE(val
)) {
317 cx
= JSD_GetDefaultJSContext(jsdc
);
318 obj
= JSVAL_TO_OBJECT(val
);
319 OBJ_TO_OUTER_OBJECT(cx
, obj
);
322 JS_ClearPendingException(cx
);
326 val
= OBJECT_TO_JSVAL(obj
);
332 static JSDProperty
* _newProperty(JSDContext
* jsdc
, JSPropertyDesc
* pd
,
333 uintN additionalFlags
)
335 JSDProperty
* jsdprop
;
337 if(!(jsdprop
= (JSDProperty
*) calloc(1, sizeof(JSDProperty
))))
340 JS_INIT_CLIST(&jsdprop
->links
);
342 jsdprop
->flags
= pd
->flags
| additionalFlags
;
343 jsdprop
->slot
= pd
->slot
;
345 if(!(jsdprop
->name
= jsd_NewValue(jsdc
, pd
->id
)))
348 if(!(jsdprop
->val
= jsd_NewValue(jsdc
, pd
->value
)))
351 if((jsdprop
->flags
& JSDPD_ALIAS
) &&
352 !(jsdprop
->alias
= jsd_NewValue(jsdc
, pd
->alias
)))
357 jsd_DropProperty(jsdc
, jsdprop
);
361 static void _freeProps(JSDContext
* jsdc
, JSDValue
* jsdval
)
363 JSDProperty
* jsdprop
;
365 while(jsdprop
= (JSDProperty
*)jsdval
->props
.next
,
366 jsdprop
!= (JSDProperty
*)&jsdval
->props
)
368 JS_REMOVE_AND_INIT_LINK(&jsdprop
->links
);
369 jsd_DropProperty(jsdc
, jsdprop
);
371 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval
->props
));
372 CLEAR_BIT_FLAG(jsdval
->flags
, GOT_PROPS
);
375 static JSBool
_buildProps(JSDContext
* jsdc
, JSDValue
* jsdval
)
377 JSContext
* cx
= jsdc
->dumbContext
;
378 JSPropertyDescArray pda
;
381 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval
->props
));
382 JS_ASSERT(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
)));
383 JS_ASSERT(JSVAL_IS_OBJECT(jsdval
->val
));
385 if(!JSVAL_IS_OBJECT(jsdval
->val
) || JSVAL_IS_NULL(jsdval
->val
))
389 if(!JS_GetPropertyDescArray(cx
, JSVAL_TO_OBJECT(jsdval
->val
), &pda
))
395 for(i
= 0; i
< pda
.length
; i
++)
397 JSDProperty
* prop
= _newProperty(jsdc
, &pda
.array
[i
], 0);
400 _freeProps(jsdc
, jsdval
);
403 JS_APPEND_LINK(&prop
->links
, &jsdval
->props
);
405 JS_PutPropertyDescArray(cx
, &pda
);
407 SET_BIT_FLAG(jsdval
->flags
, GOT_PROPS
);
408 return !JS_CLIST_IS_EMPTY(&jsdval
->props
);
411 #undef DROP_CLEAR_VALUE
412 #define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;}
415 jsd_RefreshValue(JSDContext
* jsdc
, JSDValue
* jsdval
)
417 JSContext
* cx
= jsdc
->dumbContext
;
421 /* if the jsval is a string, then we didn't need to root the string */
422 if(!JSVAL_IS_STRING(jsdval
->val
))
425 JS_RemoveRoot(cx
, &jsdval
->string
);
428 jsdval
->string
= NULL
;
431 jsdval
->funName
= NULL
;
432 jsdval
->className
= NULL
;
433 DROP_CLEAR_VALUE(jsdc
, jsdval
->proto
);
434 DROP_CLEAR_VALUE(jsdc
, jsdval
->parent
);
435 DROP_CLEAR_VALUE(jsdc
, jsdval
->ctor
);
436 _freeProps(jsdc
, jsdval
);
440 /***************************************************************************/
443 jsd_GetCountOfProperties(JSDContext
* jsdc
, JSDValue
* jsdval
)
445 JSDProperty
* jsdprop
;
448 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
)))
449 if(!_buildProps(jsdc
, jsdval
))
452 for(jsdprop
= (JSDProperty
*)jsdval
->props
.next
;
453 jsdprop
!= (JSDProperty
*)&jsdval
->props
;
454 jsdprop
= (JSDProperty
*)jsdprop
->links
.next
)
462 jsd_IterateProperties(JSDContext
* jsdc
, JSDValue
* jsdval
, JSDProperty
**iterp
)
464 JSDProperty
* jsdprop
= *iterp
;
465 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROPS
)))
468 if(!_buildProps(jsdc
, jsdval
))
473 jsdprop
= (JSDProperty
*)jsdval
->props
.next
;
474 if(jsdprop
== (JSDProperty
*)&jsdval
->props
)
476 *iterp
= (JSDProperty
*)jsdprop
->links
.next
;
484 jsd_GetValueProperty(JSDContext
* jsdc
, JSDValue
* jsdval
, JSString
* name
)
486 JSContext
* cx
= jsdc
->dumbContext
;
487 JSDProperty
* jsdprop
;
488 JSDProperty
* iter
= NULL
;
493 const jschar
* nameChars
;
497 if(!jsd_IsValueObject(jsdc
, jsdval
))
500 /* If we already have the prop, then return it */
501 while(NULL
!= (jsdprop
= jsd_IterateProperties(jsdc
, jsdval
, &iter
)))
503 JSString
* propName
= jsd_GetValueString(jsdc
, jsdprop
->name
);
504 if(propName
&& !JS_CompareStrings(propName
, name
))
506 JSD_DropProperty(jsdc
, jsdprop
);
508 /* Not found in property list, look it up explicitly */
510 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
513 nameChars
= JS_GetStringChars(name
);
514 nameLen
= JS_GetStringLength(name
);
518 JS_GetUCPropertyAttributes(cx
, obj
, nameChars
, nameLen
, &attrs
, &found
);
525 JS_ClearPendingException(cx
);
527 if(!JS_GetUCProperty(cx
, obj
, nameChars
, nameLen
, &val
))
529 if (JS_IsExceptionPending(cx
))
531 if (!JS_GetPendingException(cx
, &pd
.value
))
536 pd
.flags
= JSPD_EXCEPTION
;
540 pd
.flags
= JSPD_ERROR
;
541 pd
.value
= JSVAL_VOID
;
551 pd
.id
= STRING_TO_JSVAL(name
);
552 pd
.alias
= pd
.slot
= pd
.spare
= 0;
553 pd
.flags
|= (attrs
& JSPROP_ENUMERATE
) ? JSPD_ENUMERATE
: 0
554 | (attrs
& JSPROP_READONLY
) ? JSPD_READONLY
: 0
555 | (attrs
& JSPROP_PERMANENT
) ? JSPD_PERMANENT
: 0;
557 return _newProperty(jsdc
, &pd
, JSDPD_HINTED
);
562 jsd_GetValuePrototype(JSDContext
* jsdc
, JSDValue
* jsdval
)
564 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PROTO
)))
568 JS_ASSERT(!jsdval
->proto
);
569 SET_BIT_FLAG(jsdval
->flags
, GOT_PROTO
);
570 if(!JSVAL_IS_OBJECT(jsdval
->val
))
572 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
574 JS_BeginRequest(jsdc
->dumbContext
);
575 proto
= JS_GetPrototype(jsdc
->dumbContext
, obj
);
576 JS_EndRequest(jsdc
->dumbContext
);
579 jsdval
->proto
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(proto
));
582 jsdval
->proto
->nref
++;
583 return jsdval
->proto
;
587 jsd_GetValueParent(JSDContext
* jsdc
, JSDValue
* jsdval
)
589 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_PARENT
)))
593 JS_ASSERT(!jsdval
->parent
);
594 SET_BIT_FLAG(jsdval
->flags
, GOT_PARENT
);
595 if(!JSVAL_IS_OBJECT(jsdval
->val
))
597 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
599 JS_BeginRequest(jsdc
->dumbContext
);
600 parent
= JS_GetParent(jsdc
->dumbContext
,obj
);
601 JS_EndRequest(jsdc
->dumbContext
);
604 jsdval
->parent
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(parent
));
607 jsdval
->parent
->nref
++;
608 return jsdval
->parent
;
612 jsd_GetValueConstructor(JSDContext
* jsdc
, JSDValue
* jsdval
)
614 if(!(CHECK_BIT_FLAG(jsdval
->flags
, GOT_CTOR
)))
619 JS_ASSERT(!jsdval
->ctor
);
620 SET_BIT_FLAG(jsdval
->flags
, GOT_CTOR
);
621 if(!JSVAL_IS_OBJECT(jsdval
->val
))
623 if(!(obj
= JSVAL_TO_OBJECT(jsdval
->val
)))
625 JS_BeginRequest(jsdc
->dumbContext
);
626 proto
= JS_GetPrototype(jsdc
->dumbContext
,obj
);
629 JS_EndRequest(jsdc
->dumbContext
);
632 ctor
= JS_GetConstructor(jsdc
->dumbContext
,proto
);
633 JS_EndRequest(jsdc
->dumbContext
);
636 jsdval
->ctor
= jsd_NewValue(jsdc
, OBJECT_TO_JSVAL(ctor
));
639 jsdval
->ctor
->nref
++;
644 jsd_GetValueClassName(JSDContext
* jsdc
, JSDValue
* jsdval
)
646 jsval val
= jsdval
->val
;
647 if(!jsdval
->className
&& JSVAL_IS_OBJECT(val
))
650 if(!(obj
= JSVAL_TO_OBJECT(val
)))
652 JS_BeginRequest(jsdc
->dumbContext
);
653 if(JS_GET_CLASS(jsdc
->dumbContext
, obj
))
654 jsdval
->className
= JS_GET_CLASS(jsdc
->dumbContext
, obj
)->name
;
655 JS_EndRequest(jsdc
->dumbContext
);
657 return jsdval
->className
;
661 jsd_GetScriptForValue(JSDContext
* jsdc
, JSDValue
* jsdval
)
663 JSContext
* cx
= jsdc
->dumbContext
;
664 jsval val
= jsdval
->val
;
666 JSExceptionState
* exceptionState
;
667 JSScript
* script
= NULL
;
668 JSDScript
* jsdscript
;
670 if (!jsd_IsValueFunction(jsdc
, jsdval
))
674 exceptionState
= JS_SaveExceptionState(cx
);
675 fun
= JS_ValueToFunction(cx
, val
);
676 JS_RestoreExceptionState(cx
, exceptionState
);
678 script
= JS_GetFunctionScript(cx
, fun
);
684 JSD_LOCK_SCRIPTS(jsdc
);
685 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
686 JSD_UNLOCK_SCRIPTS(jsdc
);
691 /***************************************************************************/
692 /***************************************************************************/
695 jsd_GetPropertyName(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
697 jsdprop
->name
->nref
++;
698 return jsdprop
->name
;
702 jsd_GetPropertyValue(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
704 jsdprop
->val
->nref
++;
709 jsd_GetPropertyAlias(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
712 jsdprop
->alias
->nref
++;
713 return jsdprop
->alias
;
717 jsd_GetPropertyFlags(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
719 return jsdprop
->flags
;
723 jsd_GetPropertyVarArgSlot(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
725 return jsdprop
->slot
;
729 jsd_DropProperty(JSDContext
* jsdc
, JSDProperty
* jsdprop
)
731 JS_ASSERT(jsdprop
->nref
> 0);
732 if(0 == --jsdprop
->nref
)
734 JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop
->links
));
735 DROP_CLEAR_VALUE(jsdc
, jsdprop
->val
);
736 DROP_CLEAR_VALUE(jsdc
, jsdprop
->name
);
737 DROP_CLEAR_VALUE(jsdc
, jsdprop
->alias
);