Bug 967649 - Enable baseline compilation for with statements r=jandem
authorAndy Wingo <wingo@igalia.com>
Wed, 05 Feb 2014 15:22:13 +0100
changeset 185170 e869145b20d0ba0de7d43b5b00873328a70dd2e6
parent 185169 963f1738eaa5e04b84540ce173a8ce969e368ce3
child 185171 78426eb3c9e15fe3ce0974a91f964a91046eabd6
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs967649
milestone30.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 967649 - Enable baseline compilation for with statements r=jandem
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/BaselineFrame-inl.h
js/src/jit/BaselineFrame.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/Stack-inl.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2645,16 +2645,53 @@ BaselineCompiler::emit_JSOP_DEBUGLEAVEBL
     prepareVMCall();
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     pushArg(ImmPtr(pc));
     pushArg(R0.scratchReg());
 
     return callVM(DebugLeaveBlockInfo);
 }
 
+typedef bool (*EnterWithFn)(JSContext *, BaselineFrame *, HandleValue, Handle<StaticWithObject *>);
+static const VMFunction EnterWithInfo = FunctionInfo<EnterWithFn>(jit::EnterWith);
+
+bool
+BaselineCompiler::emit_JSOP_ENTERWITH()
+{
+    StaticWithObject &withObj = script->getObject(pc)->as<StaticWithObject>();
+
+    // Pop "with" object to R0.
+    frame.popRegsAndSync(1);
+
+    // Call a stub to push the object onto the scope chain.
+    prepareVMCall();
+    masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
+
+    pushArg(ImmGCPtr(&withObj));
+    pushArg(R0);
+    pushArg(R1.scratchReg());
+
+    return callVM(EnterWithInfo);
+}
+
+typedef bool (*LeaveWithFn)(JSContext *, BaselineFrame *);
+static const VMFunction LeaveWithInfo = FunctionInfo<LeaveWithFn>(jit::LeaveWith);
+
+bool
+BaselineCompiler::emit_JSOP_LEAVEWITH()
+{
+    // Call a stub to pop the with object from the scope chain.
+    prepareVMCall();
+
+    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
+    pushArg(R0.scratchReg());
+
+    return callVM(LeaveWithInfo);
+}
+
 typedef bool (*GetAndClearExceptionFn)(JSContext *, MutableHandleValue);
 static const VMFunction GetAndClearExceptionInfo =
     FunctionInfo<GetAndClearExceptionFn>(GetAndClearException);
 
 bool
 BaselineCompiler::emit_JSOP_EXCEPTION()
 {
     prepareVMCall();
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -22,16 +22,18 @@ namespace js {
 namespace jit {
 
 #define OPCODE_LIST(_)         \
     _(JSOP_NOP)                \
     _(JSOP_LABEL)              \
     _(JSOP_POP)                \
     _(JSOP_POPN)               \
     _(JSOP_POPNV)              \
+    _(JSOP_ENTERWITH)          \
+    _(JSOP_LEAVEWITH)          \
     _(JSOP_DUP)                \
     _(JSOP_DUP2)               \
     _(JSOP_SWAP)               \
     _(JSOP_PICK)               \
     _(JSOP_GOTO)               \
     _(JSOP_IFEQ)               \
     _(JSOP_IFNE)               \
     _(JSOP_AND)                \
--- a/js/src/jit/BaselineFrame-inl.h
+++ b/js/src/jit/BaselineFrame-inl.h
@@ -28,16 +28,26 @@ BaselineFrame::pushOnScopeChain(ScopeObj
 }
 
 inline void
 BaselineFrame::popOffScopeChain()
 {
     scopeChain_ = &scopeChain_->as<ScopeObject>().enclosingScope();
 }
 
+inline void
+BaselineFrame::popWith(JSContext *cx)
+{
+    if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
+        DebugScopes::onPopWith(this);
+
+    JS_ASSERT(scopeChain()->is<DynamicWithObject>());
+    popOffScopeChain();
+}
+
 inline bool
 BaselineFrame::pushBlock(JSContext *cx, Handle<StaticBlockObject *> block)
 {
     JS_ASSERT(block->needsClone());
 
     ClonedBlockObject *clone = ClonedBlockObject::create(cx, block, this);
     if (!clone)
         return false;
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -105,16 +105,18 @@ class BaselineFrame
 
     inline Value *addressOfScratchValue() {
         return reinterpret_cast<Value *>(&loScratchValue_);
     }
 
     inline void pushOnScopeChain(ScopeObject &scope);
     inline void popOffScopeChain();
 
+    inline void popWith(JSContext *cx);
+
     CalleeToken calleeToken() const {
         uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
         return *(CalleeToken *)pointer;
     }
     void replaceCalleeToken(CalleeToken token) {
         uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
         *(CalleeToken *)pointer = token;
     }
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -927,16 +927,29 @@ DebugLeaveBlock(JSContext *cx, BaselineF
     JS_ASSERT(frame->script()->baselineScript()->debugMode());
 
     DebugScopes::onPopBlock(cx, frame, pc);
 
     return true;
 }
 
 bool
+EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val, Handle<StaticWithObject *> templ)
+{
+    return EnterWithOperation(cx, frame, val, templ);
+}
+
+bool
+LeaveWith(JSContext *cx, BaselineFrame *frame)
+{
+    frame->popWith(cx);
+    return true;
+}
+
+bool
 InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
 {
     return frame->initForOsr(interpFrame, numStackValues);
 }
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
                                 HandleObject owner, int32_t offset)
 {
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -11,16 +11,17 @@
 
 #include "jit/CompileInfo.h"
 #include "jit/IonFrames.h"
 
 namespace js {
 
 class DeclEnvObject;
 class ForkJoinContext;
+class StaticWithObject;
 
 namespace jit {
 
 enum DataType {
     Type_Void,
     Type_Bool,
     Type_Int32,
     Type_Double,
@@ -268,16 +269,17 @@ template <> struct TypeToDataType<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<Handle<StaticWithObject *> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<StaticBlockObject *> > { 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; };
 template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
 
 // Convert argument types to properties of the argument known by the jit.
 template <class T> struct TypeToArgProperties {
     static const uint32_t result =
@@ -293,16 +295,19 @@ template <> struct TypeToArgProperties<H
     static const uint32_t result = TypeToArgProperties<JSString *>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandlePropertyName> {
     static const uint32_t result = TypeToArgProperties<PropertyName *>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandleFunction> {
     static const uint32_t result = TypeToArgProperties<JSFunction *>::result | VMFunction::ByRef;
 };
+template <> struct TypeToArgProperties<Handle<StaticWithObject *> > {
+    static const uint32_t result = TypeToArgProperties<StaticWithObject *>::result | VMFunction::ByRef;
+};
 template <> struct TypeToArgProperties<Handle<StaticBlockObject *> > {
     static const uint32_t result = TypeToArgProperties<StaticBlockObject *>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandleScript> {
     static const uint32_t result = TypeToArgProperties<JSScript *>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandleValue> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
@@ -647,16 +652,20 @@ bool HeavyweightFunPrologue(JSContext *c
 bool NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res);
 
 JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
                             HandleObject res);
 
 bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn);
 bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
 
+bool EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val,
+               Handle<StaticWithObject *> templ);
+bool LeaveWith(JSContext *cx, BaselineFrame *frame);
+
 bool PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
 bool PopBlockScope(JSContext *cx, BaselineFrame *frame);
 bool DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc);
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -826,18 +826,19 @@ js::TypeOfValue(const Value &v)
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
 /*
  * Enter the new with scope using an object at sp[-1] and associate the depth
  * of the with block with sp + stackIndex.
  */
-static bool
-EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith)
+bool
+js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val,
+                       HandleObject staticWith)
 {
     JS_ASSERT(staticWith->is<StaticWithObject>());
     RootedObject obj(cx);
     if (val.isObject()) {
         obj = &val.toObject();
     } else {
         obj = ToObject(cx, val);
         if (!obj)
@@ -1748,17 +1749,17 @@ END_CASE(JSOP_SETRVAL)
 CASE(JSOP_ENTERWITH)
 {
     RootedValue &val = rootValue0;
     RootedObject &staticWith = rootObject0;
     val = REGS.sp[-1];
     REGS.sp--;
     staticWith = script->getObject(REGS.pc);
 
-    if (!EnterWith(cx, REGS.fp(), val, staticWith))
+    if (!EnterWithOperation(cx, REGS.fp(), val, staticWith))
         goto error;
 }
 END_CASE(JSOP_ENTERWITH)
 
 CASE(JSOP_LEAVEWITH)
     REGS.fp()->popWith(cx);
 END_CASE(JSOP_LEAVEWITH)
 
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -447,16 +447,20 @@ bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id,
                           HandleObject val);
 
 bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandlePropertyName name,
                           HandleObject val);
 
 bool
+EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith);
+
+
+bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
                           HandleObject val);
 
 inline bool
 SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
 {
     return JSObject::defineProperty(cx, varobj, name, rval,
                                     JS_PropertyStub, JS_StrictPropertyStub,
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -798,20 +798,25 @@ AbstractFramePtr::popBlock(JSContext *cx
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 
 inline void
 AbstractFramePtr::popWith(JSContext *cx) const
 {
-    if (isStackFrame())
+    if (isStackFrame()) {
         asStackFrame()->popWith(cx);
-    else
-        MOZ_ASSUME_UNREACHABLE("Invalid frame");
+        return;
+    }
+#ifdef JS_ION
+    asBaselineFrame()->popWith(cx);
+#else
+    MOZ_ASSUME_UNREACHABLE("Invalid frame");
+#endif
 }
 
 Activation::Activation(JSContext *cx, Kind kind)
   : cx_(cx),
     compartment_(cx->compartment()),
     prev_(cx->mainThread().activation_),
     savedFrameChain_(0),
     hideScriptedCallerCount_(0),