Bug 1227263 part 2 - Remove this-slot from generators. r=efaust
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 26 Nov 2015 12:00:04 +0100
changeset 274267 cc18f42e01686b6b7d608ea91406f09a20e624dc
parent 274266 b5ecca6e060ce1464a58bbb87bbc872573af4914
child 274268 d10c07e6542a79b71cd08859e1df1f500a519972
push id68537
push userjandemooij@gmail.com
push dateThu, 26 Nov 2015 11:00:16 +0000
treeherdermozilla-inbound@d10c07e6542a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1227263
milestone45.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
Bug 1227263 part 2 - Remove this-slot from generators. r=efaust
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineJIT.cpp
js/src/tests/js1_7/geniter/yield-new.js
js/src/vm/GeneratorObject.cpp
js/src/vm/GeneratorObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -4023,18 +4023,18 @@ BaselineCompiler::emit_JSOP_RESUME()
     masm.branchTest32(Assembler::Zero, scratch2, scratch2, &loopDone);
     {
         masm.pushValue(UndefinedValue());
         masm.sub32(Imm32(1), scratch2);
         masm.jump(&loop);
     }
     masm.bind(&loopDone);
 
-    // Push |this|.
-    masm.pushValue(Address(genObj, GeneratorObject::offsetOfThisSlot()));
+    // Push |undefined| for |this|.
+    masm.pushValue(UndefinedValue());
 
     // Update BaselineFrame frameSize field and create the frame descriptor.
     masm.computeEffectiveAddress(Address(BaselineFrameReg, BaselineFrame::FramePointerOffset),
                                  scratch2);
     masm.subStackPtrFrom(scratch2);
     masm.store32(scratch2, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
     masm.makeFrameDescriptor(scratch2, JitFrame_BaselineJS);
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -105,19 +105,25 @@ EnterBaseline(JSContext* cx, EnterJitDat
         JS_CHECK_RECURSION(cx, return JitExec_Aborted);
     }
 
     MOZ_ASSERT(jit::IsBaselineEnabled(cx));
     MOZ_ASSERT_IF(data.osrFrame, CheckFrame(data.osrFrame));
 
     EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline();
 
-    // Caller must construct |this| before invoking the Ion function.
-    MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject() ||
-                                     data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
+    bool constructingLegacyGen =
+        data.constructing && CalleeTokenToFunction(data.calleeToken)->isLegacyGenerator();
+
+    // Caller must construct |this| before invoking the Ion function. Legacy
+    // generators can be called with 'new' but when we resume them, the
+    // this-slot and arguments are |undefined| (they are stored in the
+    // CallObject).
+    MOZ_ASSERT_IF(data.constructing && !constructingLegacyGen,
+                  data.maxArgv[0].isObject() || data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         ActivationEntryMonitor entryMonitor(cx, data.calleeToken);
         JitActivation activation(cx);
 
         if (data.osrFrame)
@@ -130,17 +136,21 @@ EnterBaseline(JSContext* cx, EnterJitDat
         if (data.osrFrame)
             data.osrFrame->clearRunningInJit();
     }
 
     MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
 
     // Jit callers wrap primitive constructor return, except for derived
     // class constructors, which are forced to do it themselves.
-    if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) {
+    if (!data.result.isMagic() &&
+        data.constructing &&
+        data.result.isPrimitive() &&
+        !constructingLegacyGen)
+    {
         MOZ_ASSERT(data.maxArgv[0].isObject());
         data.result = data.maxArgv[0];
     }
 
     // Release temporary buffer used for OSR into Ion.
     cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
 
     MOZ_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR));
--- a/js/src/tests/js1_7/geniter/yield-new.js
+++ b/js/src/tests/js1_7/geniter/yield-new.js
@@ -10,9 +10,19 @@ var g = new function() {
     yield this;
 }
 
 var ct = 0;
 for (var i in g)
     assertEq((ct < K && ct++ == i) || i == obj, true);
 assertEq(i.x, "puppies");
 
+function g2() {
+    for (var i=0; i<20; i++)
+	yield i;
+}
+var i = 0;
+for (var x of new g2()) {
+    assertEq(i, x);
+    i++;
+}
+
 reportCompare(true,true);
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -43,17 +43,16 @@ GeneratorObject::create(JSContext* cx, A
             return nullptr;
         obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto);
     }
     if (!obj)
         return nullptr;
 
     GeneratorObject* genObj = &obj->as<GeneratorObject>();
     genObj->setCallee(*frame.callee());
-    genObj->setThisValue(frame.thisArgument());
     genObj->setNewTarget(frame.newTarget());
     genObj->setScopeChain(*frame.scopeChain());
     if (frame.script()->needsArgsObj())
         genObj->setArgsObj(frame.argsObj());
     genObj->clearExpressionStack();
 
     return obj;
 }
@@ -147,20 +146,19 @@ js::GeneratorThrowOrClose(JSContext* cx,
 bool
 GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
                         HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind)
 {
     Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
     MOZ_ASSERT(genObj->isSuspended());
 
     RootedFunction callee(cx, &genObj->callee());
-    RootedValue thisv(cx, genObj->thisValue());
     RootedValue newTarget(cx, genObj->newTarget());
     RootedObject scopeChain(cx, &genObj->scopeChain());
-    if (!activation.resumeGeneratorFrame(callee, thisv, newTarget, scopeChain))
+    if (!activation.resumeGeneratorFrame(callee, newTarget, scopeChain))
         return false;
     activation.regs().fp()->setResumedGenerator();
 
     if (genObj->hasArgsObj())
         activation.regs().fp()->initArgsObj(genObj->argsObj());
 
     if (genObj->hasExpressionStack()) {
         uint32_t len = genObj->expressionStack().length();
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -21,17 +21,16 @@ class GeneratorObject : public NativeObj
   public:
     // Magic values stored in the yield index slot when the generator is
     // running or closing. See the yield index comment below.
     static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
     static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
 
     enum {
         CALLEE_SLOT = 0,
-        THIS_SLOT,
         SCOPE_CHAIN_SLOT,
         ARGS_OBJ_SLOT,
         EXPRESSION_STACK_SLOT,
         YIELD_INDEX_SLOT,
         NEWTARGET_SLOT,
         RESERVED_SLOTS
     };
 
@@ -76,23 +75,16 @@ class GeneratorObject : public NativeObj
 
     JSFunction& callee() const {
         return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
     }
     void setCallee(JSFunction& callee) {
         setFixedSlot(CALLEE_SLOT, ObjectValue(callee));
     }
 
-    const Value& thisValue() const {
-        return getFixedSlot(THIS_SLOT);
-    }
-    void setThisValue(Value& thisv) {
-        setFixedSlot(THIS_SLOT, thisv);
-    }
-
     JSObject& scopeChain() const {
         return getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
     }
     void setScopeChain(JSObject& scopeChain) {
         setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(scopeChain));
     }
 
     bool hasArgsObj() const {
@@ -174,30 +166,26 @@ class GeneratorObject : public NativeObj
         MOZ_ASSERT(isSuspended());
         return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
     }
     bool isClosed() const {
         return getFixedSlot(CALLEE_SLOT).isNull();
     }
     void setClosed() {
         setFixedSlot(CALLEE_SLOT, NullValue());
-        setFixedSlot(THIS_SLOT, NullValue());
         setFixedSlot(SCOPE_CHAIN_SLOT, NullValue());
         setFixedSlot(ARGS_OBJ_SLOT, NullValue());
         setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
         setFixedSlot(YIELD_INDEX_SLOT, NullValue());
         setFixedSlot(NEWTARGET_SLOT, NullValue());
     }
 
     static size_t offsetOfCalleeSlot() {
         return getFixedSlotOffset(CALLEE_SLOT);
     }
-    static size_t offsetOfThisSlot() {
-        return getFixedSlotOffset(THIS_SLOT);
-    }
     static size_t offsetOfScopeChainSlot() {
         return getFixedSlotOffset(SCOPE_CHAIN_SLOT);
     }
     static size_t offsetOfArgsObjSlot() {
         return getFixedSlotOffset(ARGS_OBJ_SLOT);
     }
     static size_t offsetOfYieldIndexSlot() {
         return getFixedSlotOffset(YIELD_INDEX_SLOT);
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -348,18 +348,18 @@ InterpreterStack::pushInlineFrame(JSCont
     fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, args.length(), flags);
 
     regs.prepareToRun(*fp, script);
     return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
-                                           HandleFunction callee, HandleValue thisv,
-                                           HandleValue newTarget, HandleObject scopeChain)
+                                           HandleFunction callee, HandleValue newTarget,
+                                           HandleObject scopeChain)
 {
     MOZ_ASSERT(callee->isGenerator());
     RootedScript script(cx, callee->getOrCreateScript(cx));
     InterpreterFrame* prev = regs.fp();
     jsbytecode* prevpc = regs.pc;
     Value* prevsp = regs.sp;
     MOZ_ASSERT(prev);
 
@@ -374,17 +374,17 @@ InterpreterStack::resumeGeneratorCallFra
     unsigned nvals = 2 + constructing + nformal + script->nslots();
 
     uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
     if (!buffer)
         return false;
 
     Value* argv = reinterpret_cast<Value*>(buffer) + 2;
     argv[-2] = ObjectValue(*callee);
-    argv[-1] = thisv;
+    argv[-1] = UndefinedValue();
     SetValueRangeToUndefined(argv, nformal);
     if (constructing)
         argv[nformal] = newTarget;
 
     InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(argv + nformal + constructing);
     InterpreterFrame::Flags flags = constructing ? ToFrameFlags(INITIAL_CONSTRUCT)
                                                  : ToFrameFlags(INITIAL_NONE);
     fp->mark_ = mark;
@@ -1007,21 +1007,21 @@ InterpreterActivation::popInlineFrame(In
     (void)frame; // Quell compiler warning.
     MOZ_ASSERT(regs_.fp() == frame);
     MOZ_ASSERT(regs_.fp() != entryFrame_);
 
     cx_->asJSContext()->runtime()->interpreterStack().popInlineFrame(regs_);
 }
 
 inline bool
-InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue thisv,
-                                            HandleValue newTarget, HandleObject scopeChain)
+InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
+                                            HandleObject scopeChain)
 {
     InterpreterStack& stack = cx_->asJSContext()->runtime()->interpreterStack();
-    if (!stack.resumeGeneratorCallFrame(cx_->asJSContext(), regs_, callee, thisv, newTarget, scopeChain))
+    if (!stack.resumeGeneratorCallFrame(cx_->asJSContext(), regs_, callee, newTarget, scopeChain))
         return false;
 
     MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_);
     return true;
 }
 
 inline JSContext*
 AsmJSActivation::cx()
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1066,18 +1066,18 @@ class InterpreterStack
     // The interpreter can push light-weight, "inline" frames without entering a
     // new InterpreterActivation or recursively calling Interpret.
     bool pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
                          HandleScript script, InitialFrameFlags initial);
 
     void popInlineFrame(InterpreterRegs& regs);
 
     bool resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
-                                  HandleFunction callee, HandleValue thisv,
-                                  HandleValue newTarget, HandleObject scopeChain);
+                                  HandleFunction callee, HandleValue newTarget,
+                                  HandleObject scopeChain);
 
     inline void purge(JSRuntime* rt);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return allocator_.sizeOfExcludingThis(mallocSizeOf);
     }
 };
 
@@ -1468,18 +1468,18 @@ class InterpreterActivation : public Act
   public:
     inline InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame);
     inline ~InterpreterActivation();
 
     inline bool pushInlineFrame(const CallArgs& args, HandleScript script,
                                 InitialFrameFlags initial);
     inline void popInlineFrame(InterpreterFrame* frame);
 
-    inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue thisv,
-                                     HandleValue newTarget, HandleObject scopeChain);
+    inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
+                                     HandleObject scopeChain);
 
     InterpreterFrame* current() const {
         return regs_.fp();
     }
     InterpreterRegs& regs() {
         return regs_;
     }
     InterpreterFrame* entryFrame() const {