1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
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 NPL, 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 NPL, 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_FUNCTION(jsdc->dumbContext, jsdval->val);
146
jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
148
JSContext* cx = jsdc->dumbContext;
149
jsval val = jsdval->val;
151
JSExceptionState* exceptionState;
153
if(!JSVAL_IS_OBJECT(val))
156
if(JSVAL_IS_FUNCTION(cx, val))
158
exceptionState = JS_SaveExceptionState(cx);
159
fun = JS_ValueToFunction(cx, val);
160
JS_RestoreExceptionState(cx, exceptionState);
166
return JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
168
return JSVAL_TO_OBJECT(val) && OBJ_IS_NATIVE(JSVAL_TO_OBJECT(val));
171
/***************************************************************************/
174
jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
176
jsval val = jsdval->val;
177
if(!JSVAL_IS_BOOLEAN(val))
179
return JSVAL_TO_BOOLEAN(val);
183
jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
185
jsval val = jsdval->val;
186
if(!JSVAL_IS_INT(val))
188
return JSVAL_TO_INT(val);
192
jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
194
jsval val = jsdval->val;
195
if(!JSVAL_IS_DOUBLE(val))
197
return JSVAL_TO_DOUBLE(val);
201
jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
203
JSContext* cx = jsdc->dumbContext;
204
JSExceptionState* exceptionState;
208
/* if the jsval is a string, then we don't need to double root it */
209
if(JSVAL_IS_STRING(jsdval->val))
210
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;
223
return jsdval->string;
227
jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
229
JSContext* cx = jsdc->dumbContext;
230
jsval val = jsdval->val;
232
JSExceptionState* exceptionState;
234
if(!jsdval->funName && JSVAL_IS_FUNCTION(cx, val))
236
exceptionState = JS_SaveExceptionState(cx);
237
fun = JS_ValueToFunction(cx, val);
238
JS_RestoreExceptionState(cx, exceptionState);
241
jsdval->funName = JS_GetFunctionName(fun);
243
return jsdval->funName;
246
/***************************************************************************/
249
jsd_NewValue(JSDContext* jsdc, jsval val)
253
if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
256
if(JSVAL_IS_GCTHING(val))
258
if(!JS_AddNamedRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"))
266
JS_INIT_CLIST(&jsdval->props);
272
jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
274
JS_ASSERT(jsdval->nref > 0);
275
if(0 == --jsdval->nref)
277
jsd_RefreshValue(jsdc, jsdval);
278
if(JSVAL_IS_GCTHING(jsdval->val))
279
JS_RemoveRoot(jsdc->dumbContext, &jsdval->val);
285
jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
290
static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
291
uintN additionalFlags)
293
JSDProperty* jsdprop;
295
if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
298
JS_INIT_CLIST(&jsdprop->links);
300
jsdprop->flags = pd->flags | additionalFlags;
301
jsdprop->slot = pd->slot;
303
if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
306
if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
309
if((jsdprop->flags & JSDPD_ALIAS) &&
310
!(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
315
jsd_DropProperty(jsdc, jsdprop);
319
static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
321
JSDProperty* jsdprop;
323
while(jsdprop = (JSDProperty*)jsdval->props.next,
324
jsdprop != (JSDProperty*)&jsdval->props)
326
JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
327
jsd_DropProperty(jsdc, jsdprop);
329
JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
330
CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
333
static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
335
JSContext* cx = jsdc->dumbContext;
336
JSPropertyDescArray pda;
339
JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
340
JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
341
JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));
343
if(!JSVAL_IS_OBJECT(jsdval->val) || JSVAL_IS_NULL(jsdval->val))
346
if(!JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(jsdval->val), &pda))
349
for(i = 0; i < pda.length; i++)
351
JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
354
_freeProps(jsdc, jsdval);
357
JS_APPEND_LINK(&prop->links, &jsdval->props);
359
JS_PutPropertyDescArray(cx, &pda);
360
SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
361
return !JS_CLIST_IS_EMPTY(&jsdval->props);
364
#undef DROP_CLEAR_VALUE
365
#define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;}
368
jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
370
JSContext* cx = jsdc->dumbContext;
374
/* if the jsval is a string, then we didn't need to root the string */
375
if(!JSVAL_IS_STRING(jsdval->val))
376
JS_RemoveRoot(cx, &jsdval->string);
377
jsdval->string = NULL;
380
jsdval->funName = NULL;
381
jsdval->className = NULL;
382
DROP_CLEAR_VALUE(jsdc, jsdval->proto);
383
DROP_CLEAR_VALUE(jsdc, jsdval->parent);
384
DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
385
_freeProps(jsdc, jsdval);
389
/***************************************************************************/
392
jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
394
JSDProperty* jsdprop;
397
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
398
if(!_buildProps(jsdc, jsdval))
401
for(jsdprop = (JSDProperty*)jsdval->props.next;
402
jsdprop != (JSDProperty*)&jsdval->props;
403
jsdprop = (JSDProperty*)jsdprop->links.next)
411
jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
413
JSDProperty* jsdprop = *iterp;
414
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
417
if(!_buildProps(jsdc, jsdval))
422
jsdprop = (JSDProperty*)jsdval->props.next;
423
if(jsdprop == (JSDProperty*)&jsdval->props)
425
*iterp = (JSDProperty*)jsdprop->links.next;
433
jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
435
JSContext* cx = jsdc->dumbContext;
436
JSDProperty* jsdprop;
437
JSDProperty* iter = NULL;
442
const jschar * nameChars;
446
if(!jsd_IsValueObject(jsdc, jsdval))
449
/* If we already have the prop, then return it */
450
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
452
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
453
if(propName && !JS_CompareStrings(propName, name))
455
JSD_DropProperty(jsdc, jsdprop);
457
/* Not found in property list, look it up explicitly */
459
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
462
nameChars = JS_GetStringChars(name);
463
nameLen = JS_GetStringLength(name);
465
JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
469
JS_ClearPendingException(cx);
471
if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
473
if (JS_IsExceptionPending(cx))
475
if (!JS_GetPendingException(cx, &pd.value))
477
pd.flags = JSPD_EXCEPTION;
481
pd.flags = JSPD_ERROR;
482
pd.value = JSVAL_VOID;
490
pd.id = STRING_TO_JSVAL(name);
491
pd.alias = pd.slot = pd.spare = 0;
492
pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
493
| (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0
494
| (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
496
return _newProperty(jsdc, &pd, JSDPD_HINTED);
501
jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
503
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
507
JS_ASSERT(!jsdval->proto);
508
SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
509
if(!JSVAL_IS_OBJECT(jsdval->val))
511
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
513
if(!(proto = OBJ_GET_PROTO(jsdc->dumbContext,obj)))
515
jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
518
jsdval->proto->nref++;
519
return jsdval->proto;
523
jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
525
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
529
JS_ASSERT(!jsdval->parent);
530
SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
531
if(!JSVAL_IS_OBJECT(jsdval->val))
533
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
535
if(!(parent = OBJ_GET_PARENT(jsdc->dumbContext,obj)))
537
jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
540
jsdval->parent->nref++;
541
return jsdval->parent;
545
jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
547
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
552
JS_ASSERT(!jsdval->ctor);
553
SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
554
if(!JSVAL_IS_OBJECT(jsdval->val))
556
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
558
if(!(proto = OBJ_GET_PROTO(jsdc->dumbContext,obj)))
560
if(!(ctor = JS_GetConstructor(jsdc->dumbContext,proto)))
562
jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
565
jsdval->ctor->nref++;
570
jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
572
jsval val = jsdval->val;
573
if(!jsdval->className && JSVAL_IS_OBJECT(val))
576
if(!(obj = JSVAL_TO_OBJECT(val)))
578
if(OBJ_GET_CLASS(jsdc->dumbContext, obj))
579
jsdval->className = OBJ_GET_CLASS(jsdc->dumbContext, obj)->name;
581
return jsdval->className;
584
/***************************************************************************/
585
/***************************************************************************/
588
jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
590
jsdprop->name->nref++;
591
return jsdprop->name;
595
jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
597
jsdprop->val->nref++;
602
jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
605
jsdprop->alias->nref++;
606
return jsdprop->alias;
610
jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
612
return jsdprop->flags;
616
jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop)
618
return jsdprop->slot;
622
jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
624
JS_ASSERT(jsdprop->nref > 0);
625
if(0 == --jsdprop->nref)
627
JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
628
DROP_CLEAR_VALUE(jsdc, jsdprop->val);
629
DROP_CLEAR_VALUE(jsdc, jsdprop->name);
630
DROP_CLEAR_VALUE(jsdc, jsdprop->alias);