JSProperty * js_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSProperty *prop; JSObject *obj2; jsint slot; PR_ASSERT(JS_IS_LOCKED(cx)); if (!js_LookupProperty(cx, obj, id, &obj, &prop)) return NULL; if (!prop) { prop = js_DefineProperty(cx, obj, id, #if JS_BUG_NULL_INDEX_PROPS (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0) ? JSVAL_NULL : JSVAL_VOID, #else JSVAL_VOID, #endif NULL, NULL, 0); if (!prop) return NULL; } obj2 = prop->object; slot = prop->slot; *vp = obj2->slots[slot]; if (!prop->getter(cx, obj, prop->id, vp)) return NULL; obj2->slots[slot] = *vp; return prop; }
void js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot) { JSObjectMap *map; uint32 nslots; size_t nbytes; jsval *newslots; PR_ASSERT(JS_IS_LOCKED(cx)); map = obj->map; PR_ASSERT(((JSScope *)map)->object == obj); if (map->freeslot == slot + 1) map->freeslot = slot; nslots = map->nslots; if (nslots > JS_INITIAL_NSLOTS && map->freeslot < nslots / 2) { nslots = map->freeslot; nslots += nslots / 2; nbytes = (size_t)nslots * sizeof(jsval); newslots = JS_realloc(cx, obj->slots, nbytes); if (!newslots) return; obj->slots = newslots; map->nslots = nslots; } }
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); } }
JSObject * js_FindVariableScope(JSContext *cx, JSFunction **funp) { JSStackFrame *fp; JSObject *obj, *parent, *withobj; JSClass *clasp; JSFunction *fun; PR_ASSERT(JS_IS_LOCKED(cx)); fp = cx->fp; for (obj = fp->scopeChain, withobj = NULL; ; obj = parent) { parent = OBJ_GET_PARENT(obj); clasp = obj->map->clasp; if (!parent || clasp != &js_WithClass) break; withobj = obj; } fun = (clasp == &js_FunctionClass) ? JS_GetPrivate(cx, obj) : NULL; #if JS_HAS_CALL_OBJECT if (fun && fun->script) { for (; fp && fp->fun != fun; fp = fp->down) ; if (fp) { obj = js_GetCallObject(cx, fp, parent); if (withobj) OBJ_SET_PARENT(withobj, obj); } } #endif *funp = fun; return obj; }
js_DropAtom(JSContext *cx, JSAtom *atom) { #ifdef DEBUG_DUPLICATE_ATOMS jsval key; PRHashNumber keyHash; PRHashEntry *he, **hep; key = ATOM_KEY(atom); keyHash = js_hash_atom_key((void *)key); hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void*)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif PR_ASSERT(JS_IS_LOCKED(cx)); PR_ASSERT(atom->nrefs > 0); if (atom->nrefs <= 0) return NULL; if (--atom->nrefs == 0) { PR_HashTableRemove(cx->runtime->atomState.table, atom->entry.key); #ifdef DEBUG_DUPLICATE_ATOMS hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void *)key); he = *hep; PR_ASSERT(he == NULL); #endif atom = NULL; } return atom; }
static JSAtom * js_AtomizeHashedKey(JSContext *cx, jsval key, PRHashNumber keyHash, uintN flags) { PRHashTable *table; PRHashEntry *he, **hep; JSAtom *atom; PR_ASSERT(JS_IS_LOCKED(cx)); table = cx->runtime->atomState.table; hep = PR_HashTableRawLookup(table, keyHash, (void *)key); if ((he = *hep) == NULL) { he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL); if (!he) { JS_ReportOutOfMemory(cx); return NULL; } } atom = (JSAtom *)he; #ifdef DEBUG_DUPLICATE_ATOMS hep = PR_HashTableRawLookup(table, keyHash, (void *)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif if (flags & ATOM_NOHOLD) return atom; return js_HoldAtom(cx, atom); }
void js_FinalizeObject(JSContext *cx, JSObject *obj) { JSScope *scope; PR_ASSERT(JS_IS_LOCKED(cx)); /* Cope with stillborn objects that have no scope. */ scope = (JSScope *)obj->map; if (!scope) return; #if JS_HAS_OBJ_WATCHPOINT /* Remove all watchpoints with weak links to obj. */ JS_ClearWatchPointsForObject(cx, obj); #endif /* Finalize obj first, in case it needs map and slots. */ scope->map.clasp->finalize(cx, obj); if (scope->object == obj) scope->object = NULL; /* Drop scope and free slots. */ js_DropScope(cx, scope); obj->map = NULL; JS_free(cx, obj->slots); obj->slots = NULL; }
static JSBool FindConstructor(JSContext *cx, JSClass *clasp, jsval *vp) { JSAtom *atom; JSObject *obj, *tmp; JSBool ok; PR_ASSERT(JS_IS_LOCKED(cx)); /* XXX pre-atomize in JS_InitClass! */ atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); if (!atom) return JS_FALSE; if (cx->fp && (tmp = cx->fp->scopeChain)) { /* Find the topmost object in the scope chain. */ do { obj = tmp; tmp = OBJ_GET_PARENT(obj); } while (tmp); } else { obj = cx->globalObject; if (!obj) { *vp = JSVAL_VOID; return JS_TRUE; } } ok = (js_GetProperty(cx, obj, (jsval)atom, vp) != NULL); js_DropAtom(cx, atom); return JS_TRUE; }
js_LookupProperty(JSContext *cx, JSObject *obj, jsval id, JSObject **objp, JSProperty **propp) { JSObject *pobj; PRHashNumber hash; JSScope *prevscope, *scope; JSSymbol *sym; JSClass *clasp; JSResolveOp resolve; JSNewResolveOp newresolve; PR_ASSERT(JS_IS_LOCKED(cx)); /* Handle old bug that treated empty string as zero index. */ CHECK_FOR_FUNNY_INDEX(id); /* Search scopes starting with obj and following the prototype link. */ hash = js_HashValue(id); prevscope = NULL; do { scope = (JSScope *)obj->map; if (scope == prevscope) continue; sym = scope->ops->lookup(cx, scope, id, hash); if (!sym && objp) { clasp = scope->map.clasp; resolve = clasp->resolve; if (resolve != JS_ResolveStub) { if (clasp->flags & JSCLASS_NEW_RESOLVE) { newresolve = (JSNewResolveOp)resolve; pobj = NULL; if (!newresolve(cx, obj, js_IdToValue(id), &pobj)) return JS_FALSE; if (pobj) { *objp = pobj; scope = (JSScope *)pobj->map; sym = scope->ops->lookup(cx, scope, id, hash); } } else { if (!resolve(cx, obj, js_IdToValue(id))) return JS_FALSE; scope = (JSScope *)obj->map; sym = scope->ops->lookup(cx, scope, id, hash); } } } if (sym) { *propp = sym_property(sym); return JS_TRUE; } prevscope = scope; } while ((obj = OBJ_GET_PROTO(obj)) != NULL); *propp = NULL; return JS_TRUE; }
static JSBool obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, void *closure) { JSObject *funobj; jsval argv[3]; PR_ASSERT(JS_IS_LOCKED(cx)); funobj = closure; argv[0] = id; argv[1] = old; argv[2] = *nvp; return js_Call(cx, obj, OBJECT_TO_JSVAL(funobj), 3, argv, nvp); }
JSAtom * js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags) { jsdouble *dp; PRHashTable *table; PRHashNumber keyHash; jsval key; PRHashEntry *he, **hep; JSAtom *atom; #if PR_ALIGN_OF_DOUBLE == 8 dp = &d; #else char alignbuf[16]; dp = (jsdouble *)&alignbuf[8 - ((pruword)&alignbuf & 7)]; *dp = d; #endif PR_ASSERT(JS_IS_LOCKED(cx)); table = cx->runtime->atomState.table; keyHash = HASH_DOUBLE(dp); key = DOUBLE_TO_JSVAL(dp); hep = PR_HashTableRawLookup(table, keyHash, (void *)key); if ((he = *hep) == NULL) { if (!js_NewDoubleValue(cx, d, &key)) return NULL; he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL); if (!he) { JS_ReportOutOfMemory(cx); return NULL; } } atom = (JSAtom *)he; #ifdef DEBUG_DUPLICATE_ATOMS hep = PR_HashTableRawLookup(table, keyHash, (void *)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif if (flags & ATOM_NOHOLD) return atom; return js_HoldAtom(cx, atom); }
js_alloc_symbol(void *priv, const void *key) { JSContext *cx; JSSymbol *sym; JSAtom *atom; cx = priv; PR_ASSERT(JS_IS_LOCKED(cx)); sym = JS_malloc(cx, sizeof(JSSymbol)); if (!sym) return NULL; sym->entry.key = key; if (!JSVAL_IS_INT((jsval)key)) { atom = (JSAtom *)key; js_HoldAtom(cx, atom); } return &sym->entry; }
JSBool js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp) { JSObjectMap *map; uint32 nslots; size_t nbytes; jsval *newslots; PR_ASSERT(JS_IS_LOCKED(cx)); map = obj->map; PR_ASSERT(((JSScope *)map)->object == obj); nslots = map->nslots; if (map->freeslot >= nslots) { nslots = PR_MAX(map->freeslot, nslots); if (nslots < JS_INITIAL_NSLOTS) nslots = JS_INITIAL_NSLOTS; else nslots += (nslots + 1) / 2; nbytes = (size_t)nslots * sizeof(jsval); #if defined(XP_PC) && defined _MSC_VER && _MSC_VER <= 800 if (nbytes > 60000U) { JS_ReportOutOfMemory(cx); return JS_FALSE; } #endif if (obj->slots) newslots = JS_realloc(cx, obj->slots, nbytes); else newslots = JS_malloc(cx, nbytes); if (!newslots) return JS_FALSE; obj->slots = newslots; map->nslots = nslots; } #ifdef TOO_MUCH_GC obj->slots[map->freeslot] = JSVAL_VOID; #endif *slotp = map->freeslot++; return JS_TRUE; }
js_hash_scope_add(JSContext *cx, JSScope *scope, jsval id, JSProperty *prop) { PRHashTable *table = scope->data; const void *key; PRHashNumber keyHash; PRHashEntry **hep; JSSymbol *sym, **sp; PR_ASSERT(JS_IS_LOCKED(cx)); table->allocPriv = cx; key = (const void *)id; keyHash = js_hash_id(key); hep = PR_HashTableRawLookup(table, keyHash, key); sym = (JSSymbol *) *hep; SCOPE_ADD( sym = (JSSymbol *) PR_HashTableRawAdd(table, hep, keyHash, key, NULL); if (!sym) return NULL; );
JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags) { PRHashTable *table; PRHashNumber keyHash; jsval key; PRHashEntry *he, **hep; JSAtom *atom; PR_ASSERT(JS_IS_LOCKED(cx)); table = cx->runtime->atomState.table; keyHash = js_HashString(str); key = STRING_TO_JSVAL(str); hep = PR_HashTableRawLookup(table, keyHash, (void *)key); if ((he = *hep) == NULL) { if (flags & ATOM_TMPSTR) { if (flags & ATOM_NOCOPY) str = js_NewString(cx, str->chars, str->length, 0); else str = js_NewStringCopyN(cx, str->chars, str->length, 0); if (!str) return NULL; key = STRING_TO_JSVAL(str); } he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL); if (!he) { JS_ReportOutOfMemory(cx); return NULL; } } atom = (JSAtom *)he; #ifdef DEBUG_DUPLICATE_ATOMS hep = PR_HashTableRawLookup(table, keyHash, (void *)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif if (flags & ATOM_NOHOLD) return atom; return js_HoldAtom(cx, atom); }
JSAtom * js_HoldAtom(JSContext *cx, JSAtom *atom) { #ifdef DEBUG_DUPLICATE_ATOMS jsval key; PRHashNumber keyHash; PRHashEntry *he, **hep; key = ATOM_KEY(atom); keyHash = js_hash_atom_key((void *)key); hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void*)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif PR_ASSERT(JS_IS_LOCKED(cx)); atom->nrefs++; PR_ASSERT(atom->nrefs > 0); return atom; }
JSBool js_DeleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval) { #if JS_HAS_PROP_DELETE JSProperty *prop; PR_ASSERT(JS_IS_LOCKED(cx)); if (!js_LookupProperty(cx, obj, id, NULL, &prop)) return JS_FALSE; if (!prop) return JS_TRUE; return js_DeleteProperty2(cx, obj, prop, id, rval); #else jsval null = JSVAL_NULL; *rval = JSVAL_VOID; return (js_SetProperty(cx, obj, id, &null) != NULL); #endif }