Bug 1273858 - Ion-compile JSOP_PUSHLEXICALENV/JSOP_POPLEXICALENV r=jandem
authorTed Campbell <tcampbell@mozilla.com>
Fri, 10 Feb 2017 13:49:21 -0500
changeset 344258 da80011188ed
parent 344257 0fb07ea247ba
child 344259 0a3a0f9eb773
push id31405
push userkwierso@gmail.com
push dateWed, 22 Feb 2017 22:55:38 +0000
treeherdermozilla-central@499739e68fad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1273858
milestone54.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 1273858 - Ion-compile JSOP_PUSHLEXICALENV/JSOP_POPLEXICALENV r=jandem MozReview-Commit-ID: CqD2GUGoNyY
js/src/jit/BytecodeAnalysis.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/VMFunctions.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/vm/EnvironmentObject.cpp
js/src/vm/EnvironmentObject.h
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -163,16 +163,18 @@ BytecodeAnalysis::init(TempAllocator& al
           case JSOP_STRICTSETNAME:
           case JSOP_DELNAME:
           case JSOP_GETALIASEDVAR:
           case JSOP_SETALIASEDVAR:
           case JSOP_LAMBDA:
           case JSOP_LAMBDA_ARROW:
           case JSOP_DEFFUN:
           case JSOP_DEFVAR:
+          case JSOP_PUSHLEXICALENV:
+          case JSOP_POPLEXICALENV:
             usesEnvironmentChain_ = true;
             break;
 
           case JSOP_GETGNAME:
           case JSOP_SETGNAME:
           case JSOP_STRICTSETGNAME:
             if (script_->hasNonSyntacticScope())
                 usesEnvironmentChain_ = true;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3428,16 +3428,32 @@ CodeGenerator::visitMaybeCopyElementsFor
 
 void
 CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment* lir)
 {
     Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
     masm.loadPtr(environment, ToRegister(lir->output()));
 }
 
+typedef LexicalEnvironmentObject* (*NewLexicalEnvironmentObjectFn)(JSContext*,
+                                                                   Handle<LexicalScope*>,
+                                                                   HandleObject, gc::InitialHeap);
+static const VMFunction NewLexicalEnvironmentObjectInfo =
+    FunctionInfo<NewLexicalEnvironmentObjectFn>(LexicalEnvironmentObject::create,
+                                                "LexicalEnvironmentObject::create");
+
+void
+CodeGenerator::visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir)
+{
+    pushArg(Imm32(gc::DefaultHeap));
+    pushArg(ToRegister(lir->enclosing()));
+    pushArg(ImmGCPtr(lir->mir()->scope()));
+    callVM(NewLexicalEnvironmentObjectInfo, lir);
+}
+
 void
 CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity* guard)
 {
     Register input = ToRegister(guard->input());
     Register expected = ToRegister(guard->expected());
 
     Assembler::Condition cond =
         guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -282,16 +282,17 @@ class CodeGenerator final : public CodeG
     void emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output);
     void visitConcat(LConcat* lir);
     void visitCharCodeAt(LCharCodeAt* lir);
     void visitFromCharCode(LFromCharCode* lir);
     void visitFromCodePoint(LFromCodePoint* lir);
     void visitSinCos(LSinCos *lir);
     void visitStringSplit(LStringSplit* lir);
     void visitFunctionEnvironment(LFunctionEnvironment* lir);
+    void visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir);
     void visitCallGetProperty(LCallGetProperty* lir);
     void visitCallGetElement(LCallGetElement* lir);
     void visitCallSetElement(LCallSetElement* lir);
     void visitCallInitElementArray(LCallInitElementArray* lir);
     void visitThrow(LThrow* lir);
     void visitTypeOfV(LTypeOfV* lir);
     void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
     void visitToAsync(LToAsync* lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2202,16 +2202,23 @@ IonBuilder::inspectOpcode(JSOp op)
         return jsop_lambda(info().getFunction(pc));
 
       case JSOP_LAMBDA_ARROW:
         return jsop_lambda_arrow(info().getFunction(pc));
 
       case JSOP_SETFUNNAME:
         return jsop_setfunname(GET_UINT8(pc));
 
+      case JSOP_PUSHLEXICALENV:
+        return jsop_pushlexicalenv(GET_UINT32_INDEX(pc));
+
+      case JSOP_POPLEXICALENV:
+        current->setEnvironmentChain(walkEnvironmentChain(1));
+        return Ok();
+
       case JSOP_ITER:
         return jsop_iter(GET_INT8(pc));
 
       case JSOP_MOREITER:
         return jsop_itermore();
 
       case JSOP_ISNOITER:
         return jsop_isnoiter();
@@ -2265,20 +2272,18 @@ IonBuilder::inspectOpcode(JSOp op)
         return Ok();
       }
 
       case JSOP_IS_CONSTRUCTING:
         pushConstant(MagicValue(JS_IS_CONSTRUCTING));
         return Ok();
 
 #ifdef DEBUG
-      case JSOP_PUSHLEXICALENV:
       case JSOP_FRESHENLEXICALENV:
       case JSOP_RECREATELEXICALENV:
-      case JSOP_POPLEXICALENV:
         // These opcodes are currently unhandled by Ion, but in principle
         // there's no reason they couldn't be.  Whenever this happens, OSR
         // will have to consider that JSOP_{FRESHEN,RECREATE}LEXICALENV
         // mutates the env chain -- right now MBasicBlock::environmentChain()
         // caches the env chain.  JSOP_{FRESHEN,RECREATE}LEXICALENV must
         // update that stale value.
 #endif
       default:
@@ -11845,16 +11850,31 @@ IonBuilder::jsop_setfunname(uint8_t pref
 
     current->add(ins);
     current->push(fun);
 
     return resumeAfter(ins);
 }
 
 AbortReasonOr<Ok>
+IonBuilder::jsop_pushlexicalenv(uint32_t index)
+{
+    MOZ_ASSERT(analysis().usesEnvironmentChain());
+
+    LexicalScope* scope = &script()->getScope(index)->as<LexicalScope>();
+    MNewLexicalEnvironmentObject* ins =
+        MNewLexicalEnvironmentObject::New(alloc(), current->environmentChain(), scope);
+
+    current->add(ins);
+    current->setEnvironmentChain(ins);
+
+    return resumeAfter(ins);
+}
+
+AbortReasonOr<Ok>
 IonBuilder::jsop_setarg(uint32_t arg)
 {
     // To handle this case, we should spill the arguments to the space where
     // actual arguments are stored. The tricky part is that if we add a MIR
     // to wrap the spilling action, we don't want the spilling to be
     // captured by the GETARG and by the resume point, only by
     // MGetFrameArgument.
     MOZ_ASSERT(analysis_.hasSetArg());
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -556,16 +556,17 @@ class IonBuilder
     AbortReasonOr<Ok> jsop_mutateproto();
     AbortReasonOr<Ok> jsop_initprop(PropertyName* name);
     AbortReasonOr<Ok> jsop_initprop_getter_setter(PropertyName* name);
     AbortReasonOr<Ok> jsop_regexp(RegExpObject* reobj);
     AbortReasonOr<Ok> jsop_object(JSObject* obj);
     AbortReasonOr<Ok> jsop_lambda(JSFunction* fun);
     AbortReasonOr<Ok> jsop_lambda_arrow(JSFunction* fun);
     AbortReasonOr<Ok> jsop_setfunname(uint8_t prefixKind);
+    AbortReasonOr<Ok> jsop_pushlexicalenv(uint32_t index);
     AbortReasonOr<Ok> jsop_functionthis();
     AbortReasonOr<Ok> jsop_globalthis();
     AbortReasonOr<Ok> jsop_typeof();
     AbortReasonOr<Ok> jsop_toasync();
     AbortReasonOr<Ok> jsop_toid();
     AbortReasonOr<Ok> jsop_iter(uint8_t flags);
     AbortReasonOr<Ok> jsop_itermore();
     AbortReasonOr<Ok> jsop_isnoiter();
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2513,16 +2513,29 @@ LIRGenerator::visitSetFunName(MSetFunNam
 
     LSetFunName* lir = new(alloc()) LSetFunName(useRegisterAtStart(ins->fun()),
                                                 useBoxAtStart(ins->name()));
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
+LIRGenerator::visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins)
+{
+    MDefinition* enclosing = ins->enclosing();
+    MOZ_ASSERT(enclosing->type() == MIRType::Object);
+
+    LNewLexicalEnvironmentObject* lir =
+        new(alloc()) LNewLexicalEnvironmentObject(useRegisterAtStart(enclosing));
+
+    defineReturn(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
+void
 LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins)
 {
     MDefinition* obj = ins->object();
     MOZ_ASSERT(obj->type() == MIRType::Object);
 
     add(new(alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
 }
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -181,16 +181,17 @@ class LIRGenerator : public LIRGenerator
     void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins);
     void visitStringReplace(MStringReplace* ins);
     void visitBinarySharedStub(MBinarySharedStub* ins);
     void visitUnarySharedStub(MUnarySharedStub* ins);
     void visitNullarySharedStub(MNullarySharedStub* ins);
     void visitLambda(MLambda* ins);
     void visitLambdaArrow(MLambdaArrow* ins);
     void visitSetFunName(MSetFunName* ins);
+    void visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins);
     void visitKeepAliveObject(MKeepAliveObject* ins);
     void visitSlots(MSlots* ins);
     void visitElements(MElements* ins);
     void visitConstantElements(MConstantElements* ins);
     void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins);
     void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
     void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
     void visitLoadSlot(MLoadSlot* ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11525,16 +11525,46 @@ class MFunctionEnvironment
     MDefinition* foldsTo(TempAllocator& alloc) override;
 
     // A function's environment is fixed.
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
+// Allocate a new LexicalEnvironmentObject.
+class MNewLexicalEnvironmentObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerGCPointer<LexicalScope*> scope_;
+
+    MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
+      : MUnaryInstruction(enclosing),
+        scope_(scope)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, enclosing))
+
+    LexicalScope* scope() const {
+        return scope_;
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(scope_);
+    }
+};
+
 // Store to vp[slot] (slots that are not inline in an object).
 class MStoreSlot
   : public MBinaryInstruction,
     public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
 {
     uint32_t slot_;
     MIRType slotType_;
     bool needsBarrier_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -167,16 +167,17 @@ namespace jit {
     _(Elements)                                                             \
     _(ConstantElements)                                                     \
     _(ConvertElementsToDoubles)                                             \
     _(MaybeToDoubleElement)                                                 \
     _(MaybeCopyElementsForWrite)                                            \
     _(LoadSlot)                                                             \
     _(StoreSlot)                                                            \
     _(FunctionEnvironment)                                                  \
+    _(NewLexicalEnvironmentObject)                                          \
     _(FilterTypeSet)                                                        \
     _(TypeBarrier)                                                          \
     _(MonitorTypes)                                                         \
     _(PostWriteBarrier)                                                     \
     _(PostWriteElementBarrier)                                              \
     _(GetPropertyCache)                                                     \
     _(GetPropertyPolymorphic)                                               \
     _(SetPropertyPolymorphic)                                               \
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -273,16 +273,17 @@ struct VMFunction
 
 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<NativeObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<PlainObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<InlineTypedObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<NamedLambdaObject*> { static const DataType result = Type_Object; };
+template <> struct TypeToDataType<LexicalEnvironmentObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<ArrayObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<TypedArrayObject*> { 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; };
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7045,16 +7045,34 @@ class LFunctionEnvironment : public LIns
     explicit LFunctionEnvironment(const LAllocation& function) {
         setOperand(0, function);
     }
     const LAllocation* function() {
         return getOperand(0);
     }
 };
 
+// Allocate a new LexicalEnvironmentObject.
+class LNewLexicalEnvironmentObject : public LCallInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(NewLexicalEnvironmentObject)
+
+    explicit LNewLexicalEnvironmentObject(const LAllocation& enclosing) {
+        setOperand(0, enclosing);
+    }
+    const LAllocation* enclosing() {
+        return getOperand(0);
+    }
+
+    MNewLexicalEnvironmentObject* mir() const {
+        return mir_->toNewLexicalEnvironmentObject();
+    }
+};
+
 class LCallGetProperty : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(CallGetProperty)
 
     static const size_t Value = 0;
 
     explicit LCallGetProperty(const LBoxAllocation& val) {
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -314,16 +314,17 @@
     _(ClampDToUint8)                \
     _(ClampVToUint8)                \
     _(LoadFixedSlotV)               \
     _(LoadFixedSlotT)               \
     _(LoadFixedSlotAndUnbox)        \
     _(StoreFixedSlotV)              \
     _(StoreFixedSlotT)              \
     _(FunctionEnvironment)          \
+    _(NewLexicalEnvironmentObject)  \
     _(GetPropertyCacheV)            \
     _(GetPropertyCacheT)            \
     _(GetPropertyPolymorphicV)      \
     _(GetPropertyPolymorphicT)      \
     _(BindNameCache)                \
     _(CallBindVar)                  \
     _(CallGetProperty)              \
     _(GetNameCache)                 \
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -884,18 +884,18 @@ LexicalEnvironmentObject::createTemplate
 
     if (enclosing)
         env->initEnclosingEnvironment(enclosing);
 
     return env;
 }
 
 /* static */ LexicalEnvironmentObject*
-LexicalEnvironmentObject::createTemplateObject(JSContext* cx, Handle<LexicalScope*> scope,
-                                               HandleObject enclosing, gc::InitialHeap heap)
+LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
+                                 HandleObject enclosing, gc::InitialHeap heap)
 {
     assertSameCompartment(cx, enclosing);
     MOZ_ASSERT(scope->hasEnvironment());
 
     RootedShape shape(cx, scope->environmentShape());
     LexicalEnvironmentObject* env = createTemplateObject(cx, shape, enclosing, heap);
     if (!env)
         return nullptr;
@@ -910,17 +910,17 @@ LexicalEnvironmentObject::createTemplate
     return env;
 }
 
 /* static */ LexicalEnvironmentObject*
 LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
                                  AbstractFramePtr frame)
 {
     RootedObject enclosing(cx, frame.environmentChain());
-    return createTemplateObject(cx, scope, enclosing, gc::DefaultHeap);
+    return create(cx, scope, enclosing, gc::DefaultHeap);
 }
 
 /* static */ LexicalEnvironmentObject*
 LexicalEnvironmentObject::createGlobal(JSContext* cx, Handle<GlobalObject*> global)
 {
     MOZ_ASSERT(global);
 
     RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
@@ -992,18 +992,17 @@ LexicalEnvironmentObject::createHollowFo
     return env;
 }
 
 /* static */ LexicalEnvironmentObject*
 LexicalEnvironmentObject::clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
 {
     Rooted<LexicalScope*> scope(cx, &env->scope());
     RootedObject enclosing(cx, &env->enclosingEnvironment());
-    Rooted<LexicalEnvironmentObject*> copy(cx, createTemplateObject(cx, scope, enclosing,
-                                                                    gc::TenuredHeap));
+    Rooted<LexicalEnvironmentObject*> copy(cx, create(cx, scope, enclosing, gc::TenuredHeap));
     if (!copy)
         return nullptr;
 
     // We can't assert that the clone has the same shape, because it could
     // have been reshaped by PurgeEnvironmentChain.
     MOZ_ASSERT(env->slotSpan() == copy->slotSpan());
     for (uint32_t i = JSSLOT_FREE(&class_); i < copy->slotSpan(); i++)
         copy->setSlot(i, env->getSlot(i));
@@ -1011,17 +1010,17 @@ LexicalEnvironmentObject::clone(JSContex
     return copy;
 }
 
 /* static */ LexicalEnvironmentObject*
 LexicalEnvironmentObject::recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
 {
     Rooted<LexicalScope*> scope(cx, &env->scope());
     RootedObject enclosing(cx, &env->enclosingEnvironment());
-    return createTemplateObject(cx, scope, enclosing, gc::TenuredHeap);
+    return create(cx, scope, enclosing, gc::TenuredHeap);
 }
 
 bool
 LexicalEnvironmentObject::isExtensible() const
 {
     return nonProxyIsExtensible();
 }
 
@@ -1066,18 +1065,17 @@ NamedLambdaObject::create(JSContext* cx,
 #ifdef DEBUG
     // There should be exactly one binding in the named lambda scope.
     BindingIter bi(scope);
     bi++;
     MOZ_ASSERT(bi.done());
 #endif
 
     LexicalEnvironmentObject* obj =
-        LexicalEnvironmentObject::createTemplateObject(cx, scope.as<LexicalScope>(),
-                                                       enclosing, heap);
+        LexicalEnvironmentObject::create(cx, scope.as<LexicalScope>(), enclosing, heap);
     if (!obj)
         return nullptr;
 
     obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
     return static_cast<NamedLambdaObject*>(obj);
 }
 
 /* static */ NamedLambdaObject*
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -472,21 +472,18 @@ class LexicalEnvironmentObject : public 
 
     void initScope(LexicalScope* scope) {
         MOZ_ASSERT(!isGlobal());
         MOZ_ASSERT(isSyntactic());
         initScopeUnchecked(scope);
     }
 
   public:
-    static LexicalEnvironmentObject* createTemplateObject(JSContext* cx,
-                                                          Handle<LexicalScope*> scope,
-                                                          HandleObject enclosing,
-                                                          gc::InitialHeap heap);
-
+    static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
+                                            HandleObject enclosing, gc::InitialHeap heap);
     static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
                                             AbstractFramePtr frame);
     static LexicalEnvironmentObject* createGlobal(JSContext* cx, Handle<GlobalObject*> global);
     static LexicalEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject enclosing);
     static LexicalEnvironmentObject* createHollowForDebug(JSContext* cx,
                                                           Handle<LexicalScope*> scope);
 
     // Create a new LexicalEnvironmentObject with the same enclosing env and