Bug 1522837 part 1 - Implement loadScript, emitInitializeLocals, storeFrameSizeAndPushDescriptor for BaselineInterpreterHandler. r=djvj
authorJan de Mooij <jdemooij@mozilla.com>
Sun, 03 Feb 2019 10:06:39 +0000
changeset 456583 a9e0cc55d71ad830d58994bc994b7aba1df69ac6
parent 456582 1b713c9f40d5817de78f88ac3414cc90bf7531f4
child 456584 aea9bf1be0da2f1f1746b5d5f398c9cd50cb853c
push id35492
push usercbrindusan@mozilla.com
push dateSun, 03 Feb 2019 21:40:38 +0000
treeherdermozilla-central@be2f62a541cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs1522837
milestone67.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 1522837 part 1 - Implement loadScript, emitInitializeLocals, storeFrameSizeAndPushDescriptor for BaselineInterpreterHandler. r=djvj This also removes computeFullFrameSize because we don't really need it. Differential Revision: https://phabricator.services.mozilla.com/D17644
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/JitFrames.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -367,16 +367,46 @@ MethodStatus BaselineCompiler::compile()
 #ifdef MOZ_VTUNE
   vtune::MarkScript(code, script, "baseline");
 #endif
 
   return Method_Compiled;
 }
 
 template <>
+void BaselineCompilerCodeGen::loadScript(Register dest) {
+  masm.movePtr(ImmGCPtr(handler.script()), dest);
+}
+
+template <>
+void BaselineInterpreterCodeGen::loadScript(Register dest) {
+  // TODO(bug 1522394): consider adding interpreterScript to BaselineFrame once
+  // we are able to run benchmarks.
+
+  masm.loadPtr(frame.addressOfCalleeToken(), dest);
+
+  Label notFunction, done;
+  masm.branchTestPtr(Assembler::NonZero, dest, Imm32(CalleeTokenScriptBit),
+                     &notFunction);
+  {
+    // CalleeToken_Function or CalleeToken_FunctionConstructing.
+    masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
+    masm.loadPtr(Address(dest, JSFunction::offsetOfScript()), dest);
+    masm.jump(&done);
+  }
+  masm.bind(&notFunction);
+  {
+    // CalleeToken_Script.
+    masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
+  }
+
+  masm.bind(&done);
+}
+
+template <>
 void BaselineCompilerCodeGen::emitInitializeLocals() {
   // Initialize all locals to |undefined|. Lexical bindings are temporal
   // dead zoned in bytecode.
 
   size_t n = frame.nlocals();
   if (n == 0) {
     return;
   }
@@ -408,17 +438,32 @@ void BaselineCompilerCodeGen::emitInitia
     }
     masm.branchSub32(Assembler::NonZero, Imm32(LOOP_UNROLL_FACTOR),
                      R1.scratchReg(), &pushLoop);
   }
 }
 
 template <>
 void BaselineInterpreterCodeGen::emitInitializeLocals() {
-  MOZ_CRASH("NYI: interpreter emitInitializeLocals");
+  // Push |undefined| for all locals.
+
+  Register scratch = R0.scratchReg();
+  loadScript(scratch);
+  masm.load32(Address(scratch, JSScript::offsetOfNfixed()), scratch);
+
+  Label top, done;
+  masm.bind(&top);
+  masm.branchTest32(Assembler::Zero, scratch, scratch, &done);
+  {
+    masm.pushValue(UndefinedValue());
+    masm.sub32(Imm32(1), scratch);
+    masm.jump(&top);
+  }
+
+  masm.bind(&done);
 }
 
 // On input:
 //  R2.scratchReg() contains object being written to.
 //  Called with the baseline stack synced, except for R0 which is preserved.
 //  All other registers are usable as scratch.
 // This calls:
 //    void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
@@ -502,45 +547,46 @@ void BaselineCodeGen<Handler>::prepareVM
   frame.syncStack(0);
 
   // Save the frame pointer.
   masm.Push(BaselineFrameReg);
 }
 
 template <>
 void BaselineCompilerCodeGen::storeFrameSizeAndPushDescriptor(
-    uint32_t frameBaseSize, uint32_t argSize, const Address& frameSizeAddr) {
+    uint32_t frameBaseSize, uint32_t argSize, const Address& frameSizeAddr,
+    Register scratch1, Register scratch2) {
   uint32_t frameVals = frame.nlocals() + frame.stackDepth();
 
   uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
   masm.store32(Imm32(frameFullSize), frameSizeAddr);
 
   uint32_t descriptor = MakeFrameDescriptor(
       frameFullSize + argSize, FrameType::BaselineJS, ExitFrameLayout::Size());
   masm.push(Imm32(descriptor));
 }
 
 template <>
 void BaselineInterpreterCodeGen::storeFrameSizeAndPushDescriptor(
-    uint32_t frameBaseSize, uint32_t argSize, const Address& frameSizeAddr) {
-  MOZ_CRASH("NYI: interpreter storeFrameSizeAndPushDescriptor");
-}
-
-template <>
-void BaselineCompilerCodeGen::computeFullFrameSize(uint32_t frameBaseSize,
-                                                   Register dest) {
-  uint32_t frameVals = frame.nlocals() + frame.stackDepth();
-  uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
-  masm.move32(Imm32(frameFullSize), dest);
-}
-
-template <>
-void BaselineInterpreterCodeGen::computeFullFrameSize(uint32_t frameBaseSize,
-                                                      Register dest) {
-  MOZ_CRASH("NYI: interpreter computeFullFrameSize");
+    uint32_t frameBaseSize, uint32_t argSize, const Address& frameSizeAddr,
+    Register scratch1, Register scratch2) {
+  // scratch1 = FramePointer + BaselineFrame::FramePointerOffset - StackPointer.
+  masm.computeEffectiveAddress(
+      Address(BaselineFrameReg, BaselineFrame::FramePointerOffset), scratch1);
+  masm.subStackPtrFrom(scratch1);
+
+  // Store the frame size without VMFunction arguments. Use
+  // computeEffectiveAddress instead of sub32 to avoid an extra move.
+  masm.computeEffectiveAddress(Address(scratch1, -int32_t(argSize)), scratch2);
+  masm.store32(scratch2, frameSizeAddr);
+
+  // Push frame descriptor based on the full frame size.
+  masm.makeFrameDescriptor(scratch1, FrameType::BaselineJS,
+                           ExitFrameLayout::Size());
+  masm.push(scratch1);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::callVM(const VMFunction& fun,
                                       CallVMPhase phase) {
   TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
 
 #ifdef DEBUG
@@ -567,39 +613,39 @@ bool BaselineCodeGen<Handler>::callVM(co
   // Assert all arguments were pushed.
   MOZ_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);
 
   Address frameSizeAddress(BaselineFrameReg,
                            BaselineFrame::reverseOffsetOfFrameSize());
   uint32_t frameBaseSize =
       BaselineFrame::FramePointerOffset + BaselineFrame::Size();
   if (phase == POST_INITIALIZE) {
-    storeFrameSizeAndPushDescriptor(frameBaseSize, argSize, frameSizeAddress);
+    storeFrameSizeAndPushDescriptor(frameBaseSize, argSize, frameSizeAddress,
+                                    R0.scratchReg(), R1.scratchReg());
   } else {
     MOZ_ASSERT(phase == CHECK_OVER_RECURSED);
-    Label afterWrite;
-    Label writePostInitialize;
+    Label done, pushedFrameLocals;
 
     // If OVER_RECURSED is set, then frame locals haven't been pushed yet.
     masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
-                      Imm32(BaselineFrame::OVER_RECURSED),
-                      &writePostInitialize);
-
-    masm.move32(Imm32(frameBaseSize), ICTailCallReg);
-    masm.jump(&afterWrite);
-
-    masm.bind(&writePostInitialize);
-    computeFullFrameSize(frameBaseSize, ICTailCallReg);
-
-    masm.bind(&afterWrite);
-    masm.store32(ICTailCallReg, frameSizeAddress);
-    masm.add32(Imm32(argSize), ICTailCallReg);
-    masm.makeFrameDescriptor(ICTailCallReg, FrameType::BaselineJS,
-                             ExitFrameLayout::Size());
-    masm.push(ICTailCallReg);
+                      Imm32(BaselineFrame::OVER_RECURSED), &pushedFrameLocals);
+    {
+      masm.store32(Imm32(frameBaseSize), frameSizeAddress);
+      uint32_t descriptor =
+          MakeFrameDescriptor(frameBaseSize + argSize, FrameType::BaselineJS,
+                              ExitFrameLayout::Size());
+      masm.push(Imm32(descriptor));
+      masm.jump(&done);
+    }
+    masm.bind(&pushedFrameLocals);
+    {
+      storeFrameSizeAndPushDescriptor(frameBaseSize, argSize, frameSizeAddress,
+                                      R0.scratchReg(), R1.scratchReg());
+    }
+    masm.bind(&done);
   }
   MOZ_ASSERT(fun.expectTailCall == NonTailCall);
   // Perform the call.
   masm.call(code);
   uint32_t callOffset = masm.currentOffset();
   masm.pop(BaselineFrameReg);
 
 #ifdef DEBUG
@@ -678,26 +724,16 @@ void BaselineCompilerCodeGen::emitIsDebu
 }
 
 template <>
 void BaselineInterpreterCodeGen::emitIsDebuggeeCheck() {
   MOZ_CRASH("NYI: interpreter emitIsDebuggeeCheck");
 }
 
 template <>
-void BaselineCompilerCodeGen::loadScript(Register dest) {
-  masm.movePtr(ImmGCPtr(handler.script()), dest);
-}
-
-template <>
-void BaselineInterpreterCodeGen::loadScript(Register dest) {
-  MOZ_CRASH("NYI: interpreter loadScript");
-}
-
-template <>
 void BaselineCompilerCodeGen::subtractScriptSlotsSize(Register reg,
                                                       Register scratch) {
   uint32_t slotsSize = handler.script()->nslots() * sizeof(Value);
   masm.subPtr(Imm32(slotsSize), reg);
 }
 
 template <>
 void BaselineInterpreterCodeGen::subtractScriptSlotsSize(Register reg,
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -336,18 +336,18 @@ class BaselineCodeGen {
   void pushGlobalLexicalEnvironmentValue(ValueOperand scratch);
 
   // Load the |this|-value from the global's lexical environment.
   void loadGlobalThisValue(ValueOperand dest);
 
   void prepareVMCall();
 
   void storeFrameSizeAndPushDescriptor(uint32_t frameBaseSize, uint32_t argSize,
-                                       const Address& frameSizeAddr);
-  void computeFullFrameSize(uint32_t frameBaseSize, Register dest);
+                                       const Address& frameSizeAddr,
+                                       Register scratch1, Register scratch2);
 
   enum CallVMPhase { POST_INITIALIZE, CHECK_OVER_RECURSED };
   bool callVM(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE);
 
   bool callVMNonOp(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE) {
     if (!callVM(fun, phase)) {
       return false;
     }
--- a/js/src/jit/JitFrames.h
+++ b/js/src/jit/JitFrames.h
@@ -11,23 +11,26 @@
 
 #include "jit/JSJitFrameIter.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 
 namespace js {
 namespace jit {
 
+struct SafepointSlotEntry;
+
 enum CalleeTokenTag {
   CalleeToken_Function = 0x0,  // untagged
   CalleeToken_FunctionConstructing = 0x1,
   CalleeToken_Script = 0x2
 };
 
-struct SafepointSlotEntry;
+// Any CalleeToken with this bit set must be CalleeToken_Script.
+static const uintptr_t CalleeTokenScriptBit = CalleeToken_Script;
 
 static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
 
 static inline CalleeTokenTag GetCalleeTokenTag(CalleeToken token) {
   CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
   MOZ_ASSERT(tag <= CalleeToken_Script);
   return tag;
 }