Backed out changeset 747b04228fa6 (bug 807443) because of crashes on a website when scrolling
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 Dec 2012 19:58:21 -0500
changeset 115250 6d32ee966b68db8252e4643fdc9976e3df3d347b
parent 115249 272a92957ed8cc838c49f1e7a22722b2d71c1750
child 115251 654265a8c3cedf8ed1ca199f33604182ab2e2f01
push id19236
push usereakhgari@mozilla.com
push dateFri, 07 Dec 2012 00:58:27 +0000
treeherdermozilla-inbound@6d32ee966b68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs807443
milestone20.0a1
backs out747b04228fa634553305663035edc0641b9c533d
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
Backed out changeset 747b04228fa6 (bug 807443) because of crashes on a website when scrolling
js/src/ion/Bailouts.cpp
js/src/ion/Bailouts.h
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/Ion.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/IonFrames.h
js/src/ion/LIR-Common.h
js/src/ion/LIR.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/ion/VMFunctions.h
js/src/ion/shared/CodeGenerator-shared.cpp
js/src/jit-test/tests/basic/bug522136.js
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -514,25 +514,24 @@ 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::EnsureHasScopeObjects(JSContext *cx, StackFrame *fp)
+ion::EnsureHasCallObject(JSContext *cx, StackFrame *fp)
 {
     if (fp->isFunctionFrame() &&
         fp->fun()->isHeavyweight() &&
         !fp->hasCallObj())
     {
-        return fp->initFunctionScopeObjects(cx);
+        return fp->initCallObject(cx);
     }
     return true;
 }
 
 uint32_t
 ion::BoundsCheckFailure()
 {
     JSContext *cx = GetIonContext()->cx;
@@ -592,17 +591,17 @@ ion::CachedShapeGuardFailure()
 
 uint32_t
 ion::ThunkToInterpreter(Value *vp)
 {
     JSContext *cx = GetIonContext()->cx;
     IonActivation *activation = cx->runtime->ionActivation;
     BailoutClosure *br = activation->takeBailout();
 
-    if (!EnsureHasScopeObjects(cx, cx->fp()))
+    if (!EnsureHasCallObject(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 EnsureHasScopeObjects(JSContext *cx, StackFrame *fp);
+bool EnsureHasCallObject(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
@@ -1723,40 +1723,16 @@ 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,17 +87,16 @@ 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 (!EnsureHasScopeObjects(cx, cx->fp()))
+        if (!EnsureHasCallObject(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,23 +583,20 @@ 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()) {
-            if (fun->isNamedLambda()) {
-                scope = createDeclEnvObject(scope);
-                if (!scope)
-                    return false;
-            }
+            // We don't yet support inlining of DeclEnv objects.
+            if (fun->isNamedLambda())
+                return abort("DeclEnv scope objects are not yet supported");
 
             scope = createCallObject(callee, scope);
             if (!scope)
                 return false;
         }
     } else {
         scope = MConstant::New(ObjectValue(script_->global()));
         current->add(scope);
@@ -1037,24 +1034,16 @@ 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:
@@ -3745,44 +3734,16 @@ 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;
@@ -3800,18 +3761,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::calleeSlot(), callee));
     current->add(MStoreFixedSlot::New(callObj, CallObject::enclosingScopeSlot(), scope));
-    current->add(MStoreFixedSlot::New(callObj, CallObject::calleeSlot(), callee));
 
     // 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,17 +292,16 @@ 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 -slot;
+        return sizeof(IonJSFrameLayout) + -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,32 +264,16 @@ 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,19 +360,18 @@ class LStackSlot : public LAllocation
         return kind() == DOUBLE_SLOT;
     }
 
     uint32_t slot() const {
         return data();
     }
 };
 
-// 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.
+// Arguments are reverse indexes into the stack, and like LStackSlot, each
+// index is measured in increments of STACK_SLOT_SIZE.
 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,17 +20,16 @@
     _(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,23 +154,16 @@ 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,17 +76,16 @@ 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,42 +5519,16 @@ 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,17 +66,16 @@ 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,17 +182,16 @@ 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,26 +69,24 @@ 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();
     }
-    JS_ASSERT(-int32_t(sizeof(IonJSFrameLayout)) <= a->toArgument()->index());
-    return -(sizeof(IonJSFrameLayout) + a->toArgument()->index());
+    return -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,9 +2,10 @@ 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 > 8000, true);
+assertEq(thrown && Q > 10000, true);
+
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -249,75 +249,57 @@ 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::createTemplateObject(JSContext *cx, HandleFunction fun)
+DeclEnvObject::create(JSContext *cx, StackFrame *fp)
 {
+    assertSameCompartment(cx, fp);
+
     RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL));
     if (!type)
         return NULL;
 
     RootedShape emptyDeclEnvShape(cx);
     emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL,
-                                                    cx->global(), FINALIZE_KIND,
+                                                    &fp->global(), FINALIZE_KIND,
                                                     BaseShape::DELEGATE);
     if (!emptyDeclEnvShape)
         return NULL;
 
     RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL));
     if (!obj)
         return NULL;
 
-    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))
-    {
+    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)) {
         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,31 +213,21 @@ 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 = 2;
+    static const uint32_t RESERVED_SLOTS = 1;
     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::initFunctionScopeObjects(JSContext *cx)
+StackFrame::initCallObject(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() && !initFunctionScopeObjects(cx))
+    if (fun()->isHeavyweight() && !initCallObject(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 initFunctionScopeObjects(JSContext *cx);
+    bool initCallObject(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