DeclEnvObject * DeclEnvObject::create(JSContext *cx, StackFrame *fp) { RootedVarTypeObject type(cx); type = cx->compartment->getEmptyType(cx); if (!type) return NULL; RootedVarShape emptyDeclEnvShape(cx); emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL, &fp->scopeChain().global(), FINALIZE_KIND); if (!emptyDeclEnvShape) return NULL; JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL); if (!obj) return NULL; obj->setPrivate(fp); if (!obj->asScope().setEnclosingScope(cx, fp->scopeChain())) return NULL; return &obj->asDeclEnv(); }
WithObject * WithObject::create(JSContext *cx, StackFrame *fp, JSObject &proto, JSObject &enclosing, uint32_t depth) { RootedVarTypeObject type(cx); type = proto.getNewType(cx); if (!type) return NULL; RootedVarShape emptyWithShape(cx); emptyWithShape = EmptyShape::getInitialShape(cx, &WithClass, &proto, &enclosing.global(), FINALIZE_KIND); if (!emptyWithShape) return NULL; JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyWithShape, type, NULL); if (!obj) return NULL; if (!obj->asScope().setEnclosingScope(cx, enclosing)) return NULL; obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth)); obj->setPrivate(js_FloatingFrameIfGenerator(cx, fp)); JSObject *thisp = proto.thisObject(cx); if (!thisp) return NULL; obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp)); return &obj->asWith(); }
PropertyCacheEntry * PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *pobj, const Shape *shape) { JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(!cx->runtime->gcRunning); /* * Check for fill from js_SetPropertyHelper where the setter removed shape * from pobj (via unwatch or delete, e.g.). */ if (!pobj->nativeContains(cx, *shape)) { PCMETER(oddfills++); return JS_NO_PROP_CACHE_FILL; } /* * Check for overdeep scope and prototype chain. Because resolve, getter, * and setter hooks can change the prototype chain using JS_SetPrototype * after LookupPropertyWithFlags has returned, we calculate the protoIndex * here and not in LookupPropertyWithFlags. * * The scopeIndex can't be wrong. We require JS_SetParent calls to happen * before any running script might consult a parent-linked scope chain. If * this requirement is not satisfied, the fill in progress will never hit, * but scope shape tests ensure nothing malfunctions. */ JS_ASSERT_IF(obj == pobj, scopeIndex == 0); JSObject *tmp = obj; for (uintN i = 0; i < scopeIndex; i++) tmp = &tmp->asScope().enclosingScope(); uintN protoIndex = 0; while (tmp != pobj) { /* * Don't cache entries across prototype lookups which can mutate in * arbitrary ways without a shape change. */ if (tmp->hasUncacheableProto()) { PCMETER(noprotos++); return JS_NO_PROP_CACHE_FILL; } tmp = tmp->getProto(); /* * We cannot cache properties coming from native objects behind * non-native ones on the prototype chain. The non-natives can * mutate in arbitrary way without changing any shapes. */ if (!tmp || !tmp->isNative()) { PCMETER(noprotos++); return JS_NO_PROP_CACHE_FILL; } ++protoIndex; } typedef PropertyCacheEntry Entry; if (scopeIndex > Entry::MaxScopeIndex || protoIndex > Entry::MaxProtoIndex) { PCMETER(longchains++); return JS_NO_PROP_CACHE_FILL; } /* * Optimize the cached vword based on our parameters and the current pc's * opcode format flags. */ jsbytecode *pc; (void) cx->stack.currentScript(&pc); JSOp op = JSOp(*pc); const JSCodeSpec *cs = &js_CodeSpec[op]; if ((cs->format & JOF_SET) && obj->watched()) return JS_NO_PROP_CACHE_FILL; if (obj == pobj) { JS_ASSERT(scopeIndex == 0 && protoIndex == 0); } else { #ifdef DEBUG if (scopeIndex == 0) { JS_ASSERT(protoIndex != 0); JS_ASSERT((protoIndex == 1) == (obj->getProto() == pobj)); } #endif if (scopeIndex != 0 || protoIndex != 1) { /* * Make sure that a later shadowing assignment will enter * PurgeProtoChain and invalidate this entry, bug 479198. */ if (!obj->isDelegate()) return JS_NO_PROP_CACHE_FILL; } } PropertyCacheEntry *entry = &table[hash(pc, obj->lastProperty())]; PCMETER(entry->vword.isNull() || recycles++); entry->assign(pc, obj->lastProperty(), pobj->lastProperty(), shape, scopeIndex, protoIndex); empty = false; PCMETER(fills++); /* * The modfills counter is not exact. It increases if a getter or setter * recurse into the interpreter. */ PCMETER(entry == pctestentry || modfills++); PCMETER(pctestentry = NULL); return entry; }
/* * Construct a call object for the given bindings. If this is a call object * for a function invocation, callee should be the function being called. * Otherwise it must be a call object for eval of strict mode code, and callee * must be null. */ CallObject * CallObject::create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee) { RootedVarShape shape(cx); shape = script->bindings.callObjectShape(cx); if (shape == NULL) return NULL; gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots() + 1); RootedVarTypeObject type(cx); type = cx->compartment->getEmptyType(cx); if (!type) return NULL; HeapSlot *slots; if (!PreallocateObjectDynamicSlots(cx, shape, &slots)) return NULL; JSObject *obj = JSObject::create(cx, kind, shape, type, slots); if (!obj) return NULL; /* * Update the parent for bindings associated with non-compileAndGo scripts, * whose call objects do not have a consistent global variable and need * to be updated dynamically. */ JSObject &global = enclosing.global(); if (&global != obj->getParent()) { JS_ASSERT(obj->getParent() == NULL); if (!obj->setParent(cx, &global)) return NULL; } #ifdef DEBUG JS_ASSERT(!obj->inDictionaryMode()); for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) { const Shape &s = r.front(); if (s.hasSlot()) { JS_ASSERT(s.slot() + 1 == obj->slotSpan()); break; } } #endif if (!obj->asScope().setEnclosingScope(cx, enclosing)) return NULL; JS_ASSERT_IF(callee, callee->isFunction()); obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); obj->initFixedSlot(ARGUMENTS_SLOT, MagicValue(JS_UNASSIGNED_ARGUMENTS)); /* * If |bindings| is for a function that has extensible parents, that means * its Call should have its own shape; see BaseShape::extensibleParents. */ if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx)) return NULL; return &obj->asCall(); }