js_free_symbol(void *priv, PRHashEntry *he, uintN flag) { JSContext *cx; JSSymbol *sym, **sp; JSProperty *prop; cx = priv; PR_ASSERT(JS_IS_LOCKED(cx)); sym = (JSSymbol *)he; prop = sym->entry.value; if (prop) { sym->entry.value = NULL; prop = js_DropProperty(cx, prop); if (prop) { for (sp = &prop->symbols; *sp; sp = &(*sp)->next) { if (*sp == sym) { *sp = sym->next; if (!*sp) break; } } sym->next = NULL; } } if (flag == HT_FREE_ENTRY) { if (!JSVAL_IS_INT(sym_id(sym))) JS_LOCK_VOID(cx, js_DropAtom(cx, sym_atom(sym))); JS_free(cx, he); } }
JSBool js_DeleteProperty2(JSContext *cx, JSObject *obj, JSProperty *prop, jsval id, jsval *rval) { #if JS_HAS_PROP_DELETE JSRuntime *rt; JSString *str; JSScope *scope; JSObject *proto; PRHashNumber hash; JSSymbol *sym; rt = cx->runtime; PR_ASSERT(JS_IS_RUNTIME_LOCKED(rt)); *rval = JSVERSION_IS_ECMA(cx->version) ? JSVAL_TRUE : JSVAL_VOID; if (prop->flags & JSPROP_PERMANENT) { if (JSVERSION_IS_ECMA(cx->version)) { *rval = JSVAL_FALSE; return JS_TRUE; } str = js_ValueToSource(cx, js_IdToValue(id)); if (str) JS_ReportError(cx, "%s is permanent", JS_GetStringBytes(str)); return JS_FALSE; } if (!obj->map->clasp->delProperty(cx, obj, prop->id, &prop->object->slots[prop->slot])) { return JS_FALSE; } /* Handle old bug that treated empty string as zero index. */ CHECK_FOR_FUNNY_INDEX(id); GC_POKE(cx, prop->object->slots[prop->slot]); scope = (JSScope *)obj->map; proto = scope->object; if (proto == obj) { /* The object has its own scope, so remove id if it was found here. */ if (prop->object == obj) { /* Purge cache only if prop is not about to be destroyed. */ if (prop->nrefs != 1) { PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, PROP_NOT_FOUND); } #if JS_HAS_OBJ_WATCHPOINT if (prop->setter == js_watch_set) { /* * Keep the symbol around with null value in case of re-set. * The watchpoint will hold the "deleted" property until it * is removed by obj_unwatch or a native JS_ClearWatchPoint. * See js_SetProperty for the re-set logic. */ for (sym = prop->symbols; sym; sym = sym->next) { if (sym_id(sym) == id) { sym->entry.value = NULL; prop = js_DropProperty(cx, prop); PR_ASSERT(prop); return JS_TRUE; } } } #endif scope->ops->remove(cx, scope, id); } proto = OBJ_GET_PROTO(obj); if (!proto) return JS_TRUE; } /* Search shared prototype scopes for an inherited property to hide. */ hash = js_HashValue(id); do { scope = (JSScope *)proto->map; sym = scope->ops->lookup(cx, scope, id, hash); if (sym) { /* Add a null-valued symbol to hide the prototype property. */ scope = js_GetMutableScope(cx, obj); if (!scope) return JS_FALSE; if (!scope->ops->add(cx, scope, id, NULL)) return JS_FALSE; PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, PROP_NOT_FOUND); return JS_TRUE; } proto = OBJ_GET_PROTO(proto); } while (proto); return JS_TRUE; #else jsval null = JSVAL_NULL; return (js_SetProperty(cx, obj, id, &null) != NULL); #endif }