Automated checkin: version bump remove "pre" from version number for firefox 3.7a1...
[mozilla-central.git] / js / jsd / jsd_val.c
blob1f7f8deb499c6f0db4d1f984d8451a4e65c3ff42
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"
43 #include "jsapi.h"
44 #include "jspubtd.h"
47 * Lifted with slight modification from jsobj.h
50 #define OBJ_TO_OUTER_OBJECT(cx, obj) \
51 do { \
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); \
57 } \
58 } while(0)
60 #ifdef DEBUG
61 void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
63 JS_ASSERT(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));
71 if(jsdval->proto)
73 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
74 JS_ASSERT(jsdval->proto->nref > 0);
76 if(jsdval->parent)
78 JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
79 JS_ASSERT(jsdval->parent->nref > 0);
81 if(jsdval->ctor)
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)
90 JS_ASSERT(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);
95 if(jsdprop->alias)
96 JS_ASSERT(jsdprop->alias->nref > 0);
98 #endif
101 JSBool
102 jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
104 return JSVAL_IS_OBJECT(jsdval->val);
107 JSBool
108 jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
110 return JSVAL_IS_NUMBER(jsdval->val);
113 JSBool
114 jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
116 return JSVAL_IS_INT(jsdval->val);
119 JSBool
120 jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
122 return JSVAL_IS_DOUBLE(jsdval->val);
125 JSBool
126 jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
128 return JSVAL_IS_STRING(jsdval->val);
131 JSBool
132 jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
134 return JSVAL_IS_BOOLEAN(jsdval->val);
137 JSBool
138 jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
140 return JSVAL_IS_NULL(jsdval->val);
143 JSBool
144 jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
146 return JSVAL_IS_VOID(jsdval->val);
149 JSBool
150 jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
152 return JSVAL_IS_PRIMITIVE(jsdval->val);
155 JSBool
156 jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
158 return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
159 JS_ObjectIsFunction(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
162 JSBool
163 jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
165 JSContext* cx = jsdc->dumbContext;
166 jsval val = jsdval->val;
167 JSFunction* fun;
168 JSExceptionState* exceptionState;
170 if(jsd_IsValueFunction(jsdc, jsdval))
172 JSBool ok = JS_FALSE;
173 JS_BeginRequest(cx);
174 exceptionState = JS_SaveExceptionState(cx);
175 fun = JS_ValueToFunction(cx, val);
176 JS_RestoreExceptionState(cx, exceptionState);
177 if(fun)
178 ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
179 JS_EndRequest(cx);
180 JS_ASSERT(fun);
181 return ok;
183 return !JSVAL_IS_PRIMITIVE(val);
186 /***************************************************************************/
188 JSBool
189 jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
191 jsval val = jsdval->val;
192 if(!JSVAL_IS_BOOLEAN(val))
193 return JS_FALSE;
194 return JSVAL_TO_BOOLEAN(val);
197 int32
198 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
200 jsval val = jsdval->val;
201 if(!JSVAL_IS_INT(val))
202 return 0;
203 return JSVAL_TO_INT(val);
206 jsdouble*
207 jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
209 jsval val = jsdval->val;
210 if(!JSVAL_IS_DOUBLE(val))
211 return 0;
212 return JSVAL_TO_DOUBLE(val);
215 JSString*
216 jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
218 JSContext* cx = jsdc->dumbContext;
219 JSExceptionState* exceptionState;
221 if(!jsdval->string)
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);
226 else
228 JS_BeginRequest(cx);
229 exceptionState = JS_SaveExceptionState(cx);
230 jsdval->string = JS_ValueToString(cx, jsdval->val);
231 JS_RestoreExceptionState(cx, exceptionState);
232 if(jsdval->string)
234 if(!JS_AddNamedRoot(cx, &jsdval->string, "ValueString"))
235 jsdval->string = NULL;
237 JS_EndRequest(cx);
240 return jsdval->string;
243 const char*
244 jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
246 JSContext* cx = jsdc->dumbContext;
247 JSFunction* fun;
248 JSExceptionState* exceptionState;
250 if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
252 JS_BeginRequest(cx);
253 exceptionState = JS_SaveExceptionState(cx);
254 fun = JS_ValueToFunction(cx, jsdval->val);
255 JS_RestoreExceptionState(cx, exceptionState);
256 JS_EndRequest(cx);
257 if(!fun)
258 return NULL;
259 jsdval->funName = JS_GetFunctionName(fun);
261 return jsdval->funName;
264 /***************************************************************************/
266 JSDValue*
267 jsd_NewValue(JSDContext* jsdc, jsval val)
269 JSDValue* jsdval;
271 if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
272 return NULL;
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);
280 if(!ok)
282 free(jsdval);
283 return NULL;
286 jsdval->val = val;
287 jsdval->nref = 1;
288 JS_INIT_CLIST(&jsdval->props);
290 return jsdval;
293 void
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);
306 free(jsdval);
310 jsval
311 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
313 JSObject* obj;
314 JSContext* cx;
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);
320 if (!obj)
322 JS_ClearPendingException(cx);
323 val = JSVAL_NULL;
325 else
326 val = OBJECT_TO_JSVAL(obj);
329 return val;
332 static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
333 uintN additionalFlags)
335 JSDProperty* jsdprop;
337 if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
338 return NULL;
340 JS_INIT_CLIST(&jsdprop->links);
341 jsdprop->nref = 1;
342 jsdprop->flags = pd->flags | additionalFlags;
343 jsdprop->slot = pd->slot;
345 if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
346 goto new_prop_fail;
348 if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
349 goto new_prop_fail;
351 if((jsdprop->flags & JSDPD_ALIAS) &&
352 !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
353 goto new_prop_fail;
355 return jsdprop;
356 new_prop_fail:
357 jsd_DropProperty(jsdc, jsdprop);
358 return NULL;
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;
379 uintN i;
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))
386 return JS_FALSE;
388 JS_BeginRequest(cx);
389 if(!JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(jsdval->val), &pda))
391 JS_EndRequest(cx);
392 return JS_FALSE;
395 for(i = 0; i < pda.length; i++)
397 JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
398 if(!prop)
400 _freeProps(jsdc, jsdval);
401 break;
403 JS_APPEND_LINK(&prop->links, &jsdval->props);
405 JS_PutPropertyDescArray(cx, &pda);
406 JS_EndRequest(cx);
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;}
414 void
415 jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
417 JSContext* cx = jsdc->dumbContext;
419 if(jsdval->string)
421 /* if the jsval is a string, then we didn't need to root the string */
422 if(!JSVAL_IS_STRING(jsdval->val))
424 JS_BeginRequest(cx);
425 JS_RemoveRoot(cx, &jsdval->string);
426 JS_EndRequest(cx);
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);
437 jsdval->flags = 0;
440 /***************************************************************************/
442 uintN
443 jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
445 JSDProperty* jsdprop;
446 uintN count = 0;
448 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
449 if(!_buildProps(jsdc, jsdval))
450 return 0;
452 for(jsdprop = (JSDProperty*)jsdval->props.next;
453 jsdprop != (JSDProperty*)&jsdval->props;
454 jsdprop = (JSDProperty*)jsdprop->links.next)
456 count++;
458 return count;
461 JSDProperty*
462 jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
464 JSDProperty* jsdprop = *iterp;
465 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
467 JS_ASSERT(!jsdprop);
468 if(!_buildProps(jsdc, jsdval))
469 return NULL;
472 if(!jsdprop)
473 jsdprop = (JSDProperty*)jsdval->props.next;
474 if(jsdprop == (JSDProperty*)&jsdval->props)
475 return NULL;
476 *iterp = (JSDProperty*)jsdprop->links.next;
478 JS_ASSERT(jsdprop);
479 jsdprop->nref++;
480 return jsdprop;
483 JSDProperty*
484 jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
486 JSContext* cx = jsdc->dumbContext;
487 JSDProperty* jsdprop;
488 JSDProperty* iter = NULL;
489 JSObject* obj;
490 uintN attrs = 0;
491 JSBool found;
492 JSPropertyDesc pd;
493 const jschar * nameChars;
494 size_t nameLen;
495 jsval val;
497 if(!jsd_IsValueObject(jsdc, jsdval))
498 return NULL;
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))
505 return jsdprop;
506 JSD_DropProperty(jsdc, jsdprop);
508 /* Not found in property list, look it up explicitly */
510 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
511 return NULL;
513 nameChars = JS_GetStringChars(name);
514 nameLen = JS_GetStringLength(name);
516 JS_BeginRequest(cx);
518 JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
519 if (!found)
521 JS_EndRequest(cx);
522 return NULL;
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))
533 JS_EndRequest(cx);
534 return NULL;
536 pd.flags = JSPD_EXCEPTION;
538 else
540 pd.flags = JSPD_ERROR;
541 pd.value = JSVAL_VOID;
544 else
546 pd.value = val;
549 JS_EndRequest(cx);
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);
561 JSDValue*
562 jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
564 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
566 JSObject* obj;
567 JSObject* proto;
568 JS_ASSERT(!jsdval->proto);
569 SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
570 if(!JSVAL_IS_OBJECT(jsdval->val))
571 return NULL;
572 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
573 return NULL;
574 JS_BeginRequest(jsdc->dumbContext);
575 proto = JS_GetPrototype(jsdc->dumbContext, obj);
576 JS_EndRequest(jsdc->dumbContext);
577 if(!proto)
578 return NULL;
579 jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
581 if(jsdval->proto)
582 jsdval->proto->nref++;
583 return jsdval->proto;
586 JSDValue*
587 jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
589 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
591 JSObject* obj;
592 JSObject* parent;
593 JS_ASSERT(!jsdval->parent);
594 SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
595 if(!JSVAL_IS_OBJECT(jsdval->val))
596 return NULL;
597 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
598 return NULL;
599 JS_BeginRequest(jsdc->dumbContext);
600 parent = JS_GetParent(jsdc->dumbContext,obj);
601 JS_EndRequest(jsdc->dumbContext);
602 if(!parent)
603 return NULL;
604 jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
606 if(jsdval->parent)
607 jsdval->parent->nref++;
608 return jsdval->parent;
611 JSDValue*
612 jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
614 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
616 JSObject* obj;
617 JSObject* proto;
618 JSObject* ctor;
619 JS_ASSERT(!jsdval->ctor);
620 SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
621 if(!JSVAL_IS_OBJECT(jsdval->val))
622 return NULL;
623 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
624 return NULL;
625 JS_BeginRequest(jsdc->dumbContext);
626 proto = JS_GetPrototype(jsdc->dumbContext,obj);
627 if(!proto)
629 JS_EndRequest(jsdc->dumbContext);
630 return NULL;
632 ctor = JS_GetConstructor(jsdc->dumbContext,proto);
633 JS_EndRequest(jsdc->dumbContext);
634 if(!ctor)
635 return NULL;
636 jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
638 if(jsdval->ctor)
639 jsdval->ctor->nref++;
640 return jsdval->ctor;
643 const char*
644 jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
646 jsval val = jsdval->val;
647 if(!jsdval->className && JSVAL_IS_OBJECT(val))
649 JSObject* obj;
650 if(!(obj = JSVAL_TO_OBJECT(val)))
651 return NULL;
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;
660 JSDScript*
661 jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
663 JSContext* cx = jsdc->dumbContext;
664 jsval val = jsdval->val;
665 JSFunction* fun;
666 JSExceptionState* exceptionState;
667 JSScript* script = NULL;
668 JSDScript* jsdscript;
670 if (!jsd_IsValueFunction(jsdc, jsdval))
671 return NULL;
673 JS_BeginRequest(cx);
674 exceptionState = JS_SaveExceptionState(cx);
675 fun = JS_ValueToFunction(cx, val);
676 JS_RestoreExceptionState(cx, exceptionState);
677 if (fun)
678 script = JS_GetFunctionScript(cx, fun);
679 JS_EndRequest(cx);
681 if (!script)
682 return NULL;
684 JSD_LOCK_SCRIPTS(jsdc);
685 jsdscript = jsd_FindJSDScript(jsdc, script);
686 JSD_UNLOCK_SCRIPTS(jsdc);
687 return jsdscript;
691 /***************************************************************************/
692 /***************************************************************************/
694 JSDValue*
695 jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
697 jsdprop->name->nref++;
698 return jsdprop->name;
701 JSDValue*
702 jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
704 jsdprop->val->nref++;
705 return jsdprop->val;
708 JSDValue*
709 jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
711 if(jsdprop->alias)
712 jsdprop->alias->nref++;
713 return jsdprop->alias;
716 uintN
717 jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
719 return jsdprop->flags;
722 uintN
723 jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop)
725 return jsdprop->slot;
728 void
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);
738 free(jsdprop);