☠☠ backed out by 6d32ee966b68 ☠ ☠ | |
author | Nicolas B. Pierron <nicolas.b.pierron@mozilla.com> |
Wed, 05 Dec 2012 22:50:20 -0800 (2012-12-06) | |
changeset 115163 | 747b04228fa634553305663035edc0641b9c533d |
parent 115162 | 2971c45877a749edd9e43f645e7259800d6f97f5 |
child 115164 | 3e3b0aa054745aaa9569c0c3e198724bc1da47fd |
push id | 19183 |
push user | npierron@mozilla.com |
push date | Thu, 06 Dec 2012 06:56:30 +0000 (2012-12-06) |
treeherder | mozilla-inbound@747b04228fa6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dvander |
bugs | 807443 |
milestone | 20.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/ion/Bailouts.cpp +++ b/js/src/ion/Bailouts.cpp @@ -514,24 +514,25 @@ ion::RecompileForInlining() return BAILOUT_RETURN_FATAL_ERROR; // Invalidation should not reset the use count. JS_ASSERT(script->getUseCount() >= js_IonOptions.usesBeforeInlining); return true; } +// Initialize the decl env Object and the call object of the current frame. bool -ion::EnsureHasCallObject(JSContext *cx, StackFrame *fp) +ion::EnsureHasScopeObjects(JSContext *cx, StackFrame *fp) { if (fp->isFunctionFrame() && fp->fun()->isHeavyweight() && !fp->hasCallObj()) { - return fp->initCallObject(cx); + return fp->initFunctionScopeObjects(cx); } return true; } uint32_t ion::BoundsCheckFailure() { JSContext *cx = GetIonContext()->cx; @@ -591,17 +592,17 @@ ion::CachedShapeGuardFailure() uint32_t ion::ThunkToInterpreter(Value *vp) { JSContext *cx = GetIonContext()->cx; IonActivation *activation = cx->runtime->ionActivation; BailoutClosure *br = activation->takeBailout(); - if (!EnsureHasCallObject(cx, cx->fp())) + if (!EnsureHasScopeObjects(cx, cx->fp())) return Interpret_Error; // By default we set the forbidOsr flag on the ion script, but if a GC // happens just after we re-enter the interpreter, the ion script get // invalidated and we do not see the forbidOsr flag. This may cause a loop // which apear with eager compilation and gc zeal enabled. This code is a // workaround to avoid recompiling with OSR just after a bailout followed by // a GC. (see Bug 746691 & Bug 751383)
--- a/js/src/ion/Bailouts.h +++ b/js/src/ion/Bailouts.h @@ -199,17 +199,17 @@ class IonBailoutIterator : public IonFra if (topIonScript_) return topIonScript_; return IonFrameIterator::ionScript(); } void dump() const; }; -bool EnsureHasCallObject(JSContext *cx, StackFrame *fp); +bool EnsureHasScopeObjects(JSContext *cx, StackFrame *fp); // Called from a bailout thunk. Returns a BAILOUT_* error code. uint32_t Bailout(BailoutStack *sp); // Called from the invalidation thunk. Returns a BAILOUT_* error code. uint32_t InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut); // Called from a bailout thunk. Interprets the frame(s) that have been bailed
--- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -1721,16 +1721,40 @@ bool CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject *ool) { if (!visitNewObjectVMCall(ool->lir())) return false; masm.jump(ool->rejoin()); return true; } +typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction); +static const VMFunction NewDeclEnvObjectInfo = + FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject); + +bool +CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir) +{ + Register obj = ToRegister(lir->output()); + JSObject *templateObj = lir->mir()->templateObj(); + CompileInfo &info = lir->mir()->block()->info(); + + // If we have a template object, we can inline call object creation. + OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir, + (ArgList(), ImmGCPtr(info.fun())), + StoreRegisterTo(obj)); + if (!ool) + return false; + + masm.newGCThing(obj, templateObj, ool->entry()); + masm.initGCThing(obj, templateObj); + masm.bind(ool->rejoin()); + return true; +} + typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, HandleTypeObject, HeapSlot *); static const VMFunction NewCallObjectInfo = FunctionInfo<NewCallObjectFn>(NewCallObject); bool CodeGenerator::visitNewCallObject(LNewCallObject *lir) {
--- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -87,16 +87,17 @@ class CodeGenerator : public CodeGenerat bool visitDoubleToInt32(LDoubleToInt32 *lir); bool visitNewSlots(LNewSlots *lir); bool visitNewArrayCallVM(LNewArray *lir); bool visitNewArray(LNewArray *lir); bool visitOutOfLineNewArray(OutOfLineNewArray *ool); bool visitNewObjectVMCall(LNewObject *lir); bool visitNewObject(LNewObject *lir); bool visitOutOfLineNewObject(OutOfLineNewObject *ool); + bool visitNewDeclEnvObject(LNewDeclEnvObject *lir); bool visitNewCallObject(LNewCallObject *lir); bool visitNewStringObject(LNewStringObject *lir); bool visitInitProp(LInitProp *lir); bool visitCreateThis(LCreateThis *lir); bool visitCreateThisVM(LCreateThisVM *lir); bool visitReturnFromCtor(LReturnFromCtor *lir); bool visitArrayLength(LArrayLength *lir); bool visitTypedArrayLength(LTypedArrayLength *lir);
--- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -1522,17 +1522,17 @@ EnterIon(JSContext *cx, StackFrame *fp, IonActivation activation(cx, fp); JSAutoResolveFlags rf(cx, RESOLVE_INFER); AutoFlushInhibitor afi(cx->compartment->ionCompartment()); // Single transition point from Interpreter to Ion. enter(jitcode, maxArgc, maxArgv, fp, calleeToken, &result); } if (result.isMagic() && result.whyMagic() == JS_ION_BAILOUT) { - if (!EnsureHasCallObject(cx, cx->fp())) + if (!EnsureHasScopeObjects(cx, cx->fp())) return IonExec_Error; return IonExec_Bailout; } JS_ASSERT(fp == cx->fp()); JS_ASSERT(!cx->runtime->hasIonReturnOverride()); // The trampoline wrote the return value but did not set the HAS_RVAL flag.
--- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -583,20 +583,23 @@ IonBuilder::initScopeChain() if (JSFunction *fun = info().fun()) { MCallee *callee = MCallee::New(); current->add(callee); scope = MFunctionEnvironment::New(callee); current->add(scope); + // This reproduce what is done in CallObject::createForFunction if (fun->isHeavyweight()) { - // We don't yet support inlining of DeclEnv objects. - if (fun->isNamedLambda()) - return abort("DeclEnv scope objects are not yet supported"); + if (fun->isNamedLambda()) { + scope = createDeclEnvObject(scope); + if (!scope) + return false; + } scope = createCallObject(callee, scope); if (!scope) return false; } } else { scope = MConstant::New(ObjectValue(script_->global())); current->add(scope); @@ -1034,16 +1037,24 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_length(); case JSOP_NOT: return jsop_not(); case JSOP_THIS: return jsop_this(); + case JSOP_CALLEE: + { + MCallee *callee = MCallee::New(); + current->add(callee); + current->push(callee); + return callee; + } + case JSOP_GETPROP: case JSOP_CALLPROP: { RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName()); return jsop_getprop(name); } case JSOP_SETPROP: @@ -3734,16 +3745,44 @@ IonBuilder::inlineScriptedCall(AutoObjec // -2 for callee/this // +1 for retval JS_ASSERT(current->stackDepth() == origStackDepth - argc - 1); return true; } MInstruction * +IonBuilder::createDeclEnvObject(MDefinition *scope) +{ + // Create a template CallObject that we'll use to generate inline object + // creation. + + RootedScript script(cx, script_); + RootedFunction fun(cx, info().fun()); + RootedObject templateObj(cx, DeclEnvObject::createTemplateObject(cx, fun)); + if (!templateObj) + return NULL; + + // One field is added to the function to handle its name. This cannot be a + // dynamic slot because there is still plenty of room on the DeclEnv object. + JS_ASSERT(!templateObj->hasDynamicSlots()); + + // Allocate the actual object. It is important that no intervening + // instructions could potentially bailout, thus leaking the dynamic slots + // pointer. + MInstruction *declEnvObj = MNewDeclEnvObject::New(templateObj); + current->add(declEnvObj); + + // Initialize the object's reserved slots. + current->add(MStoreFixedSlot::New(declEnvObj, DeclEnvObject::enclosingScopeSlot(), scope)); + + return declEnvObj; +} + +MInstruction * IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) { // Create a template CallObject that we'll use to generate inline object // creation. RootedObject templateObj(cx, CallObject::createTemplateObject(cx, script_)); if (!templateObj) return NULL; @@ -3761,18 +3800,18 @@ IonBuilder::createCallObject(MDefinition // Allocate the actual object. It is important that no intervening // instructions could potentially bailout, thus leaking the dynamic slots // pointer. MInstruction *callObj = MNewCallObject::New(templateObj, slots); current->add(callObj); // Initialize the object's reserved slots. + current->add(MStoreFixedSlot::New(callObj, CallObject::enclosingScopeSlot(), scope)); current->add(MStoreFixedSlot::New(callObj, CallObject::calleeSlot(), callee)); - current->add(MStoreFixedSlot::New(callObj, CallObject::enclosingScopeSlot(), scope)); // Initialize argument slots. for (AliasedFormalIter i(script_); i; i++) { unsigned slot = i.scopeSlot(); unsigned formal = i.frameIndex(); MDefinition *param = current->getSlot(info().argSlot(formal)); if (slot >= templateObj->numFixedSlots()) current->add(MStoreSlot::New(slots, slot - templateObj->numFixedSlots(), param));
--- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -292,16 +292,17 @@ class IonBuilder : public MIRGenerator void monitorResult(MInstruction *ins, types::TypeSet *barrier, types::TypeSet *types); JSObject *getSingletonPrototype(JSFunction *target); MDefinition *createThisNative(); MDefinition *createThisScripted(MDefinition *callee); MDefinition *createThisScriptedSingleton(HandleFunction target, HandleObject proto, MDefinition *callee); MDefinition *createThis(HandleFunction target, MDefinition *callee); + MInstruction *createDeclEnvObject(MDefinition *scopeObj); MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj); bool makeCall(HandleFunction target, uint32_t argc, bool constructing); MDefinition *walkScopeChain(unsigned hops); MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length); MInstruction *addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind);
--- a/js/src/ion/IonFrames.h +++ b/js/src/ion/IonFrames.h @@ -279,17 +279,17 @@ GetPcScript(JSContext *cx, MutableHandle // Given a slot index, returns the offset, in bytes, of that slot from an // IonJSFrameLayout. Slot distances are uniform across architectures, however, // the distance does depend on the size of the frame header. static inline int32_t OffsetOfFrameSlot(int32_t slot) { if (slot <= 0) - return sizeof(IonJSFrameLayout) + -slot; + return -slot; return -(slot * STACK_SLOT_SIZE); } static inline uintptr_t ReadFrameSlot(IonJSFrameLayout *fp, int32_t slot) { return *(uintptr_t *)((char *)fp + OffsetOfFrameSlot(slot)); }
--- a/js/src/ion/LIR-Common.h +++ b/js/src/ion/LIR-Common.h @@ -264,16 +264,32 @@ class LNewObject : public LInstructionHe public: LIR_HEADER(NewObject); MNewObject *mir() const { return mir_->toNewObject(); } }; +// Allocates a new DeclEnvObject. +// +// This instruction generates two possible instruction sets: +// (1) An inline allocation of the call object is attempted. +// (2) Otherwise, a callVM create a new object. +// +class LNewDeclEnvObject : public LInstructionHelper<1, 0, 0> +{ + public: + LIR_HEADER(NewDeclEnvObject); + + MNewDeclEnvObject *mir() const { + return mir_->toNewDeclEnvObject(); + } +}; + // Allocates a new CallObject. The inputs are: // slots: either a reg representing a HeapSlot *, or a placeholder // meaning that no slots pointer is needed. // // This instruction generates two possible instruction sets: // (1) If the call object is extensible, this is a callVM to create the // call object. // (2) Otherwise, an inline allocation of the call object is attempted.
--- a/js/src/ion/LIR.h +++ b/js/src/ion/LIR.h @@ -360,18 +360,19 @@ class LStackSlot : public LAllocation return kind() == DOUBLE_SLOT; } uint32_t slot() const { return data(); } }; -// Arguments are reverse indexes into the stack, and like LStackSlot, each -// index is measured in increments of STACK_SLOT_SIZE. +// Arguments are reverse indexes into the stack, and as opposed to LStackSlot, +// each index is measured in bytes because we have to index the middle of a +// Value on 32 bits architectures. class LArgument : public LAllocation { public: explicit LArgument(int32_t index) : LAllocation(ARGUMENT, index) { } int32_t index() const {
--- a/js/src/ion/LOpcodes.h +++ b/js/src/ion/LOpcodes.h @@ -20,16 +20,17 @@ _(Parameter) \ _(Callee) \ _(TableSwitch) \ _(TableSwitchV) \ _(Goto) \ _(NewArray) \ _(NewObject) \ _(NewSlots) \ + _(NewDeclEnvObject) \ _(NewCallObject) \ _(NewStringObject) \ _(InitProp) \ _(CheckOverRecursed) \ _(RecompileCheck) \ _(DefVar) \ _(CallKnown) \ _(CallGeneric) \
--- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -154,16 +154,23 @@ LIRGenerator::visitNewArray(MNewArray *i bool LIRGenerator::visitNewObject(MNewObject *ins) { LNewObject *lir = new LNewObject(); return define(lir, ins) && assignSafepoint(lir, ins); } bool +LIRGenerator::visitNewDeclEnvObject(MNewDeclEnvObject *ins) +{ + LNewDeclEnvObject *lir = new LNewDeclEnvObject(); + return define(lir, ins) && assignSafepoint(lir, ins); +} + +bool LIRGenerator::visitNewCallObject(MNewCallObject *ins) { LAllocation slots; if (ins->slots()->type() == MIRType_Slots) slots = useRegister(ins->slots()); else slots = LConstantIndex::Bogus();
--- a/js/src/ion/Lowering.h +++ b/js/src/ion/Lowering.h @@ -76,16 +76,17 @@ class LIRGenerator : public LIRGenerator // intercept without a bunch of explicit gunk in the .cpp. bool visitParameter(MParameter *param); bool visitCallee(MCallee *callee); bool visitGoto(MGoto *ins); bool visitTableSwitch(MTableSwitch *tableswitch); bool visitNewSlots(MNewSlots *ins); bool visitNewArray(MNewArray *ins); bool visitNewObject(MNewObject *ins); + bool visitNewDeclEnvObject(MNewDeclEnvObject *ins); bool visitNewCallObject(MNewCallObject *ins); bool visitNewStringObject(MNewStringObject *ins); bool visitInitProp(MInitProp *ins); bool visitCheckOverRecursed(MCheckOverRecursed *ins); bool visitDefVar(MDefVar *ins); bool visitPrepareCall(MPrepareCall *ins); bool visitPassArg(MPassArg *arg); bool visitCreateThis(MCreateThis *ins);
--- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -5519,16 +5519,42 @@ class MNewSlots : public MNullaryInstruc unsigned nslots() const { return nslots_; } AliasSet getAliasSet() const { return AliasSet::None(); } }; +class MNewDeclEnvObject : public MNullaryInstruction +{ + CompilerRootObject templateObj_; + + MNewDeclEnvObject(HandleObject templateObj) + : MNullaryInstruction(), + templateObj_(templateObj) + { + setResultType(MIRType_Object); + } + + public: + INSTRUCTION_HEADER(NewDeclEnvObject); + + static MNewDeclEnvObject *New(HandleObject templateObj) { + return new MNewDeclEnvObject(templateObj); + } + + JSObject *templateObj() { + return templateObj_; + } + AliasSet getAliasSet() const { + return AliasSet::None(); + } +}; + class MNewCallObject : public MUnaryInstruction { CompilerRootObject templateObj_; MNewCallObject(HandleObject templateObj, MDefinition *slots) : MUnaryInstruction(slots), templateObj_(templateObj) {
--- a/js/src/ion/MOpcodes.h +++ b/js/src/ion/MOpcodes.h @@ -66,16 +66,17 @@ namespace ion { _(GuardString) \ _(ToDouble) \ _(ToInt32) \ _(TruncateToInt32) \ _(ToString) \ _(NewSlots) \ _(NewArray) \ _(NewObject) \ + _(NewDeclEnvObject) \ _(NewCallObject) \ _(NewStringObject) \ _(InitProp) \ _(Start) \ _(OsrEntry) \ _(Nop) \ _(RegExp) \ _(RegExpTest) \
--- a/js/src/ion/VMFunctions.h +++ b/js/src/ion/VMFunctions.h @@ -182,16 +182,17 @@ struct VMFunction private: // Add this to the global list of VMFunctions. void addToFunctions(); }; template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ }; template <> struct TypeToDataType<bool> { static const DataType result = Type_Bool; }; template <> struct TypeToDataType<JSObject *> { static const DataType result = Type_Object; }; +template <> struct TypeToDataType<DeclEnvObject *> { static const DataType result = Type_Object; }; template <> struct TypeToDataType<JSString *> { static const DataType result = Type_Object; }; template <> struct TypeToDataType<JSFlatString *> { static const DataType result = Type_Object; }; template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; }; template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; }; template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; }; template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; }; template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; }; template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
--- a/js/src/ion/shared/CodeGenerator-shared.cpp +++ b/js/src/ion/shared/CodeGenerator-shared.cpp @@ -69,24 +69,26 @@ CodeGeneratorShared::addOutOfLineCode(Ou // because they're probably not relevant any more. if (oolIns) code->setSource(oolIns->script(), oolIns->pc()); else code->setSource(current ? current->mir()->info().script() : NULL, lastPC_); return outOfLineCode_.append(code); } +// see OffsetOfFrameSlot static inline int32_t ToStackIndex(LAllocation *a) { if (a->isStackSlot()) { JS_ASSERT(a->toStackSlot()->slot() >= 1); return a->toStackSlot()->slot(); } - return -a->toArgument()->index(); + JS_ASSERT(-int32_t(sizeof(IonJSFrameLayout)) <= a->toArgument()->index()); + return -(sizeof(IonJSFrameLayout) + a->toArgument()->index()); } bool CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex) { IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u", resumePoint->numOperands(), (void *) resumePoint, *startIndex);
--- a/js/src/jit-test/tests/basic/bug522136.js +++ b/js/src/jit-test/tests/basic/bug522136.js @@ -2,10 +2,9 @@ var Q = 0; var thrown = false; try { (function f(i) { Q = i; if (i == 200000) return; f(i+1); })(1) } catch (e) { thrown = true; } // Exact behavior of recursion check depends on which JIT we use. -assertEq(thrown && Q > 10000, true); - +assertEq(thrown && Q > 8000, true);
--- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -249,57 +249,75 @@ JS_PUBLIC_DATA(Class) js::CallClass = { JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, NULL /* convert: Leave it NULL so we notice if calls ever escape */ }; Class js::DeclEnvClass = { js_Object_str, - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(DeclEnvObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; +/* + * Create a DeclEnvObject for a JSScript that is not initialized to any + * particular callsite. This object can either be initialized (with an enclosing + * scope and callee) or used as a template for jit compilation. + */ DeclEnvObject * -DeclEnvObject::create(JSContext *cx, StackFrame *fp) +DeclEnvObject::createTemplateObject(JSContext *cx, HandleFunction fun) { - assertSameCompartment(cx, fp); - RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL)); if (!type) return NULL; RootedShape emptyDeclEnvShape(cx); emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL, - &fp->global(), FINALIZE_KIND, + cx->global(), FINALIZE_KIND, BaseShape::DELEGATE); if (!emptyDeclEnvShape) return NULL; RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL)); if (!obj) return NULL; - obj->asScope().setEnclosingScope(fp->scopeChain()); - Rooted<jsid> id(cx, AtomToId(fp->fun()->atom())); - RootedValue value(cx, ObjectValue(fp->callee())); - if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL, - JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY, - 0, 0)) { + Rooted<jsid> id(cx, AtomToId(fun->atom())); + Class *clasp = obj->getClass(); + unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY; + if (!obj->putProperty(cx, id, clasp->getProperty, clasp->setProperty, + lambdaSlot(), attrs, 0, 0)) + { return NULL; } + obj->setFixedSlot(lambdaSlot(), ObjectValue(*fun.get())); + JS_ASSERT(!obj->hasDynamicSlots()); + return &obj->asDeclEnv(); +} + +DeclEnvObject * +DeclEnvObject::create(JSContext *cx, StackFrame *fp) +{ + assertSameCompartment(cx, fp); + + RootedFunction fun(cx, fp->fun()); + RootedObject obj(cx, createTemplateObject(cx, fun)); + if (!obj) + return NULL; + + obj->asScope().setEnclosingScope(fp->scopeChain()); return &obj->asDeclEnv(); } WithObject * WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, uint32_t depth) { RootedTypeObject type(cx, proto->getNewType(cx)); if (!type)
--- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -213,21 +213,31 @@ class CallObject : public ScopeObject static inline size_t offsetOfCallee(); static inline size_t calleeSlot() { return CALLEE_SLOT; } }; class DeclEnvObject : public ScopeObject { + // Pre-allocated slot for the named lambda. + static const uint32_t LAMBDA_SLOT = 1; + public: - static const uint32_t RESERVED_SLOTS = 1; + static const uint32_t RESERVED_SLOTS = 2; static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT2; + static DeclEnvObject * + createTemplateObject(JSContext *cx, HandleFunction fun); + static DeclEnvObject *create(JSContext *cx, StackFrame *fp); + + static inline size_t lambdaSlot() { + return LAMBDA_SLOT; + } }; class NestedScopeObject : public ScopeObject { protected: static const unsigned DEPTH_SLOT = 1; public:
--- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -262,17 +262,17 @@ AssertDynamicScopeMatchesStaticScope(JSS /* * Ideally, we'd JS_ASSERT(!scope->isScope()) but the enclosing lexical * scope chain stops at eval() boundaries. See StaticScopeIter comment. */ #endif } bool -StackFrame::initCallObject(JSContext *cx) +StackFrame::initFunctionScopeObjects(JSContext *cx) { CallObject *callobj = CallObject::createForFunction(cx, this); if (!callobj) return false; pushOnScopeChain(*callobj); flags_ |= HAS_CALL_OBJ; return true; } @@ -300,17 +300,17 @@ StackFrame::prologue(JSContext *cx, bool if (isGlobalFrame()) { Probes::enterScript(cx, script, NULL, this); return true; } JS_ASSERT(isNonEvalFunctionFrame()); AssertDynamicScopeMatchesStaticScope(script, scopeChain()); - if (fun()->isHeavyweight() && !initCallObject(cx)) + if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx)) return false; if (isConstructing()) { RootedObject callee(cx, &this->callee()); JSObject *obj = js_CreateThisForFunction(cx, callee, newType); if (!obj) return false; functionThis() = ObjectValue(*obj);
--- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -381,17 +381,17 @@ class StackFrame void epilogue(JSContext *cx); /* Subsets of 'prologue' called from jit code. */ inline bool jitHeavyweightFunctionPrologue(JSContext *cx); bool jitStrictEvalPrologue(JSContext *cx); /* Called from IonMonkey to transition from bailouts. */ void initFromBailout(JSContext *cx, ion::SnapshotIterator &iter); - bool initCallObject(JSContext *cx); + bool initFunctionScopeObjects(JSContext *cx); /* Initialize local variables of newly-pushed frame. */ void initVarsToUndefined(); /* * Stack frame type * * A stack frame may have one of three types, which determines which