Bug 1227263 part 3 - Remove this-slot from non-function frames. r=efaust
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 26 Nov 2015 12:00:05 +0100
changeset 274268 d10c07e6542a79b71cd08859e1df1f500a519972
parent 274267 cc18f42e01686b6b7d608ea91406f09a20e624dc
child 274269 8680266bbc0a5bb4b3508de5065b57ae1cfb7e49
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 3 - Remove this-slot from non-function frames. r=efaust
js/src/jit/BaselineFrame.h
js/src/jit/Ion.cpp
js/src/jit/JitFrames.cpp
js/src/jit/JitFrames.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -431,17 +431,17 @@ class BaselineFrame
     // Methods below are used by the compiler.
     static size_t offsetOfCalleeToken() {
         return FramePointerOffset + js::jit::JitFrameLayout::offsetOfCalleeToken();
     }
     static size_t offsetOfThis() {
         return FramePointerOffset + js::jit::JitFrameLayout::offsetOfThis();
     }
     static size_t offsetOfEvalNewTarget() {
-        return offsetOfArg(0);
+        return FramePointerOffset + js::jit::JitFrameLayout::offsetOfEvalNewTarget();
     }
     static size_t offsetOfArg(size_t index) {
         return FramePointerOffset + js::jit::JitFrameLayout::offsetOfActualArg(index);
     }
     static size_t offsetOfNumActualArgs() {
         return FramePointerOffset + js::jit::JitFrameLayout::offsetOfNumActualArgs();
     }
     static size_t Size() {
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2738,36 +2738,35 @@ jit::SetEnterJitData(JSContext* cx, Ente
                 vals.infallibleAppend(args.newTarget());
 
             MOZ_ASSERT(vals.length() >= numFormals + 1 + data.constructing);
             data.maxArgv = vals.begin();
         }
     } else {
         data.constructing = false;
         data.numActualArgs = 0;
-        data.maxArgc = 1;
-        data.maxArgv = state.asExecute()->addressOfThisv();
+        data.maxArgc = 0;
+        data.maxArgv = nullptr;
         data.scopeChain = state.asExecute()->scopeChain();
 
         data.calleeToken = CalleeToToken(state.script());
 
         if (state.script()->isForEval() &&
             !(state.asExecute()->type() & InterpreterFrame::GLOBAL))
         {
             ScriptFrameIter iter(cx);
             if (iter.isFunctionFrame())
                 data.calleeToken = CalleeToToken(iter.callee(cx), /* constructing = */ false);
 
-            // Push newTarget onto the stack, as well as Argv.
-            if (!vals.reserve(2))
+            // Push newTarget onto the stack.
+            if (!vals.reserve(1))
                 return false;
 
-            data.maxArgc = 2;
+            data.maxArgc = 1;
             data.maxArgv = vals.begin();
-            vals.infallibleAppend(state.asExecute()->thisv());
             if (iter.isFunctionFrame()) {
                 if (state.asExecute()->newTarget().isNull())
                     vals.infallibleAppend(iter.newTarget());
                 else
                     vals.infallibleAppend(state.asExecute()->newTarget());
             } else {
                 vals.infallibleAppend(NullValue());
             }
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1050,29 +1050,31 @@ MarkThisAndArguments(JSTracer* trc, cons
     // formal arguments is taken care of by the frame's safepoint/snapshot,
     // except when the script might have lazy arguments, in which case we mark
     // them as well. We also have to mark formals if we have a LazyLink frame.
 
     JitFrameLayout* layout = frame.isExitFrameLayout<LazyLinkExitFrameLayout>()
                              ? frame.exitFrame()->as<LazyLinkExitFrameLayout>()->jsFrame()
                              : frame.jsFrame();
 
+    if (!CalleeTokenIsFunction(layout->calleeToken()))
+        return;
+
     size_t nargs = layout->numActualArgs();
     size_t nformals = 0;
-    size_t newTargetOffset = 0;
-    if (CalleeTokenIsFunction(layout->calleeToken())) {
-        JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
-        if (!frame.isExitFrameLayout<LazyLinkExitFrameLayout>() &&
-            !fun->nonLazyScript()->argumentsHasVarBinding())
-        {
-            nformals = fun->nargs();
-        }
-        newTargetOffset = Max(nargs, fun->nargs());
+
+    JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
+    if (!frame.isExitFrameLayout<LazyLinkExitFrameLayout>() &&
+        !fun->nonLazyScript()->argumentsHasVarBinding())
+    {
+        nformals = fun->nargs();
     }
 
+    size_t newTargetOffset = Max(nargs, fun->nargs());
+
     Value* argv = layout->argv();
 
     // Trace |this|.
     TraceRoot(trc, argv, "ion-thisv");
 
     // Trace actual arguments beyond the formals. Note + 1 for thisv.
     for (size_t i = nformals + 1; i < nargs + 1; i++)
         TraceRoot(trc, &argv[i], "ion-argv");
--- a/js/src/jit/JitFrames.h
+++ b/js/src/jit/JitFrames.h
@@ -382,27 +382,32 @@ class JitFrameLayout : public CommonFram
         return offsetof(JitFrameLayout, calleeToken_);
     }
     static size_t offsetOfNumActualArgs() {
         return offsetof(JitFrameLayout, numActualArgs_);
     }
     static size_t offsetOfThis() {
         return sizeof(JitFrameLayout);
     }
+    static size_t offsetOfEvalNewTarget() {
+        return sizeof(JitFrameLayout);
+    }
     static size_t offsetOfActualArgs() {
         return offsetOfThis() + sizeof(Value);
     }
     static size_t offsetOfActualArg(size_t arg) {
         return offsetOfActualArgs() + arg * sizeof(Value);
     }
 
     Value thisv() {
+        MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
         return argv()[0];
     }
     Value* argv() {
+        MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
         return (Value*)(this + 1);
     }
     uintptr_t numActualArgs() const {
         return numActualArgs_;
     }
 
     // Computes a reference to a stack or argument slot, where a slot is a
     // distance from the base frame pointer, as would be used for LStackSlot
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -336,17 +336,17 @@ InterpreterFrame*
 InvokeState::pushInterpreterFrame(JSContext* cx)
 {
     return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, initial_);
 }
 
 InterpreterFrame*
 ExecuteState::pushInterpreterFrame(JSContext* cx)
 {
-    return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, thisv_, newTargetValue_,
+    return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, newTargetValue_,
                                                               scopeChain_, type_, evalInFrame_);
 }
 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
 // avoid this.
 #ifdef _MSC_VER
 # pragma optimize("g", off)
 #endif
@@ -640,22 +640,18 @@ js::ExecuteKernel(JSContext* cx, HandleS
     }
 
     if (script->isEmpty()) {
         if (result)
             result->setUndefined();
         return true;
     }
 
-    // It doesn't matter what we pass as thisv, global/eval scripts get |this|
-    // from the scope chain. TODO: remove thisv from ExecuteState.
-    RootedValue thisv(cx);
-
     probes::StartExecution(script);
-    ExecuteState state(cx, script, thisv, newTargetValue, scopeChainArg, type, evalInFrame, result);
+    ExecuteState state(cx, script, newTargetValue, scopeChainArg, type, evalInFrame, result);
     bool ok = RunScript(cx, state);
     probes::StopExecution(script);
 
     return ok;
 }
 
 bool
 js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value* rval)
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -166,38 +166,34 @@ class RunState
     void operator=(const RunState& other) = delete;
 };
 
 // Eval or global script.
 class ExecuteState : public RunState
 {
     ExecuteType type_;
 
-    RootedValue thisv_;
     RootedValue newTargetValue_;
     RootedObject scopeChain_;
 
     AbstractFramePtr evalInFrame_;
     Value* result_;
 
   public:
-    ExecuteState(JSContext* cx, JSScript* script, const Value& thisv, const Value& newTargetValue,
+    ExecuteState(JSContext* cx, JSScript* script, const Value& newTargetValue,
                  JSObject& scopeChain, ExecuteType type, AbstractFramePtr evalInFrame,
                  Value* result)
       : RunState(cx, Execute, script),
         type_(type),
-        thisv_(cx, thisv),
         newTargetValue_(cx, newTargetValue),
         scopeChain_(cx, &scopeChain),
         evalInFrame_(evalInFrame),
         result_(result)
     { }
 
-    Value* addressOfThisv() { return thisv_.address(); }
-    Value thisv() { return thisv_; }
     Value newTarget() { return newTargetValue_; }
     JSObject* scopeChain() const { return scopeChain_; }
     ExecuteType type() const { return type_; }
 
     virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx);
 
     virtual void setReturnValue(Value v) {
         if (result_)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -29,21 +29,19 @@ using namespace js;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
 
 /*****************************************************************************/
 
 void
 InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr evalInFramePrev,
-                                   const Value& thisv, const Value& newTargetValue, HandleObject scopeChain,
+                                   const Value& newTargetValue, HandleObject scopeChain,
                                    ExecuteType type)
 {
-    MOZ_ASSERT_IF(type & MODULE, thisv.isUndefined());
-
     /*
      * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
      * script in the context of another frame and the frame type is determined
      * by the context.
      */
     flags_ = type | HAS_SCOPECHAIN;
 
     JSObject* callee = nullptr;
@@ -72,18 +70,17 @@ InterpreterFrame::initExecuteFrame(JSCon
                 callee = iter.callee(cx);
                 flags_ |= FUNCTION;
             } else {
                 flags_ |= GLOBAL;
             }
         }
     }
 
-    Value* dstvp = (Value*)this - 3;
-    dstvp[2] = thisv;
+    Value* dstvp = (Value*)this - 2;
 
     if (isFunctionFrame()) {
         dstvp[1] = ObjectValue(*callee);
         exec.fun = &callee->as<JSFunction>();
         u.evalScript = script;
     } else {
         MOZ_ASSERT(isGlobalFrame() || isModuleFrame());
         dstvp[1] = NullValue();
@@ -449,18 +446,18 @@ InterpreterFrame::markValues(JSTracer* t
         markValues(trc, 0, nlivefixed);
     }
 
     if (hasArgs()) {
         // Mark callee, |this| and arguments.
         unsigned argc = Max(numActualArgs(), numFormalArgs());
         TraceRootRange(trc, argc + 2 + isConstructing(), argv_ - 2, "fp argv");
     } else {
-        // Mark callee, |this|, and newTarget
-        TraceRootRange(trc, 3, ((Value*)this) - 3, "stack callee, this, newTarget");
+        // Mark callee and newTarget
+        TraceRootRange(trc, 2, ((Value*)this) - 2, "stack callee and newTarget");
     }
 }
 
 static void
 MarkInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
 {
     for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
         InterpreterFrame* fp = frames.frame();
@@ -507,30 +504,30 @@ InterpreterStack::pushInvokeFrame(JSCont
         return nullptr;
 
     fp->mark_ = mark;
     fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
     return fp;
 }
 
 InterpreterFrame*
-InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Value& thisv,
-                                   const Value& newTargetValue, HandleObject scopeChain,
-                                   ExecuteType type, AbstractFramePtr evalInFrame)
+InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Value& newTargetValue,
+                                   HandleObject scopeChain, ExecuteType type,
+                                   AbstractFramePtr evalInFrame)
 {
     LifoAlloc::Mark mark = allocator_.mark();
 
-    unsigned nvars = 3 /* callee, this, newTarget */ + script->nslots();
+    unsigned nvars = 2 /* callee, newTarget */ + script->nslots();
     uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
     if (!buffer)
         return nullptr;
 
-    InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer + 3 * sizeof(Value));
+    InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer + 2 * sizeof(Value));
     fp->mark_ = mark;
-    fp->initExecuteFrame(cx, script, evalInFrame, thisv, newTargetValue, scopeChain, type);
+    fp->initExecuteFrame(cx, script, evalInFrame, newTargetValue, scopeChain, type);
     fp->initLocals();
 
     return fp;
 }
 
 /*****************************************************************************/
 
 void
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -422,18 +422,17 @@ class InterpreterFrame
 
     /* Used for Invoke and Interpret. */
     void initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc, Value* prevsp,
                        JSFunction& callee, JSScript* script, Value* argv, uint32_t nactual,
                        InterpreterFrame::Flags flags);
 
     /* Used for global and eval frames. */
     void initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr prev,
-                          const Value& thisv, const Value& newTargetValue,
-                          HandleObject scopeChain, ExecuteType type);
+                          const Value& newTargetValue, HandleObject scopeChain, ExecuteType type);
 
   public:
     /*
      * Frame prologue/epilogue
      *
      * Every stack frame must have 'prologue' called before executing the
      * first op and 'epilogue' called after executing the last op and before
      * popping the frame (whether the exit is exceptional or not).
@@ -737,44 +736,40 @@ class InterpreterFrame
 
     const Value& calleev() const {
         MOZ_ASSERT(isFunctionFrame());
         return mutableCalleev();
     }
 
     const Value& maybeCalleev() const {
         Value& calleev = flags_ & (EVAL | GLOBAL)
-                         ? ((Value*)this)[-2]
+                         ? ((Value*)this)[-1]
                          : argv()[-2];
         MOZ_ASSERT(calleev.isObjectOrNull());
         return calleev;
     }
 
     Value& mutableCalleev() const {
         MOZ_ASSERT(isFunctionFrame());
         if (isEvalFrame())
-            return ((Value*)this)[-2];
+            return ((Value*)this)[-1];
         return argv()[-2];
     }
 
-    CallReceiver callReceiver() const {
-        return CallReceiverFromArgv(argv());
-    }
-
     /*
      * New Target
      *
      * Only function frames have a meaningful newTarget. An eval frame in a
      * function will have a copy of the newTarget of the enclosing function
      * frame.
      */
     Value newTarget() const {
         MOZ_ASSERT(isFunctionFrame());
         if (isEvalFrame())
-            return ((Value*)this)[-3];
+            return ((Value*)this)[-2];
 
         if (callee().isArrow())
             return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
 
         if (isConstructing()) {
             unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
             return argv()[pushedArgs];
         }
@@ -1050,19 +1045,19 @@ class InterpreterStack
         frameCount_(0)
     { }
 
     ~InterpreterStack() {
         MOZ_ASSERT(frameCount_ == 0);
     }
 
     // For execution of eval or global code.
-    InterpreterFrame* pushExecuteFrame(JSContext* cx, HandleScript script, const Value& thisv,
-                                 const Value& newTargetValue, HandleObject scopeChain,
-                                 ExecuteType type, AbstractFramePtr evalInFrame);
+    InterpreterFrame* pushExecuteFrame(JSContext* cx, HandleScript script,
+                                       const Value& newTargetValue, HandleObject scopeChain,
+                                       ExecuteType type, AbstractFramePtr evalInFrame);
 
     // Called to invoke a function.
     InterpreterFrame* pushInvokeFrame(JSContext* cx, const CallArgs& args,
                                       InitialFrameFlags initial);
 
     // 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,