Bug 819299: Add handling of MagicValue(JS_IS_CONSTRUCTING) to MCreateThis, r=dvander
authorHannes Verschore <hv1989@gmail.com>
Sun, 09 Dec 2012 22:57:01 +0100
changeset 115630 01414463877ccb70d581c6e57ac395271afdb490
parent 115617 478cdc0fc59f74792a1c0f0ccb935729fe0741f9
child 115631 32a37874bfd96585d81bee87a67dd745000ee593
push id24020
push useremorley@mozilla.com
push dateWed, 12 Dec 2012 10:01:41 +0000
treeherdermozilla-central@634180132e68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs819299
milestone20.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 819299: Add handling of MagicValue(JS_IS_CONSTRUCTING) to MCreateThis, r=dvander
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonMacroAssembler.h
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1837,20 +1837,18 @@ CodeGenerator::visitInitProp(LInitProp *
     return callVM(InitPropInfo, lir);
 }
 
 typedef JSObject *(*NewGCThingFn)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize);
 static const VMFunction NewGCThingInfo =
     FunctionInfo<NewGCThingFn>(js::ion::NewGCThing);
 
 bool
-CodeGenerator::visitCreateThis(LCreateThis *lir)
+CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
 {
-    JS_ASSERT(lir->mir()->hasTemplateObject());
-
     JSObject *templateObject = lir->mir()->getTemplateObject();
     gc::AllocKind allocKind = templateObject->getAllocKind();
     int thingSize = (int)gc::Arena::thingSize(allocKind);
     Register objReg = ToRegister(lir->output());
 
     OutOfLineCode *ool = oolCallVM(NewGCThingInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(thingSize)),
                                    StoreRegisterTo(objReg));
@@ -1867,38 +1865,65 @@ CodeGenerator::visitCreateThis(LCreateTh
     return true;
 }
 
 typedef JSObject *(*CreateThisFn)(JSContext *cx, HandleObject callee, JSObject *proto);
 static const VMFunction CreateThisInfo =
     FunctionInfo<CreateThisFn>(js_CreateThisForFunctionWithProto);
 
 bool
-CodeGenerator::visitCreateThisVM(LCreateThisVM *lir)
+CodeGenerator::emitCreateThisVM(LInstruction *lir,
+                                const LAllocation *proto,
+                                const LAllocation *callee)
 {
-    const LAllocation *proto = lir->getPrototype();
-    const LAllocation *callee = lir->getCallee();
-
-    // Push arguments.
     if (proto->isConstant())
         pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
     else
         pushArg(ToRegister(proto));
 
     if (callee->isConstant())
         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
     else
         pushArg(ToRegister(callee));
 
-    if (!callVM(CreateThisInfo, lir))
+    return callVM(CreateThisInfo, lir);
+}
+
+bool
+CodeGenerator::visitCreateThisV(LCreateThisV *lir)
+{
+    Label done, vm;
+
+    const LAllocation *proto = lir->getPrototype();
+    const LAllocation *callee = lir->getCallee();
+
+    // When callee could be a native, put MagicValue in return operand.
+    // Use the VMCall when callee turns out to not be a native.
+    masm.branchIfInterpreted(ToRegister(callee), &vm);
+    masm.moveValue(MagicValue(JS_IS_CONSTRUCTING), GetValueOutput(lir));
+    masm.jump(&done);
+
+    masm.bind(&vm);
+    if (!emitCreateThisVM(lir, proto, callee))
         return false;
+
+    masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, GetValueOutput(lir));
+
+    masm.bind(&done);
+
     return true;
 }
 
 bool
+CodeGenerator::visitCreateThisO(LCreateThisO *lir)
+{
+    return emitCreateThisVM(lir, lir->getPrototype(), lir->getCallee());
+}
+
+bool
 CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
 {
     ValueOperand value = ToValue(lir, LReturnFromCtor::ValueIndex);
     Register obj = ToRegister(lir->getObject());
     Register output = ToRegister(lir->output());
 
     Label valueIsObject, end;
 
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -91,18 +91,20 @@ class CodeGenerator : public CodeGenerat
     bool visitOutOfLineNewArray(OutOfLineNewArray *ool);
     bool visitNewObjectVMCall(LNewObject *lir);
     bool visitNewObject(LNewObject *lir);
     bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
     bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     bool visitNewCallObject(LNewCallObject *lir);
     bool visitNewStringObject(LNewStringObject *lir);
     bool visitInitProp(LInitProp *lir);
-    bool visitCreateThis(LCreateThis *lir);
-    bool visitCreateThisVM(LCreateThisVM *lir);
+    bool emitCreateThisVM(LInstruction *lir, const LAllocation *proto, const LAllocation *callee);
+    bool visitCreateThisV(LCreateThisV *lir);
+    bool visitCreateThisO(LCreateThisO *lir);
+    bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
     bool visitReturnFromCtor(LReturnFromCtor *lir);
     bool visitArrayLength(LArrayLength *lir);
     bool visitTypedArrayLength(LTypedArrayLength *lir);
     bool visitTypedArrayElements(LTypedArrayElements *lir);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
     bool visitSetInitializedLength(LSetInitializedLength *lir);
     bool visitNotV(LNotV *ins);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -3848,17 +3848,17 @@ IonBuilder::createThisScripted(MDefiniti
     } else {
         MCallGetProperty *callGetProp = MCallGetProperty::New(callee, cx->names().classPrototype);
         callGetProp->setIdempotent();
         getProto = callGetProp;
     }
     current->add(getProto);
 
     // Create this from prototype
-    MCreateThis *createThis = MCreateThis::New(callee, getProto, NULL);
+    MCreateThis *createThis = MCreateThis::New(callee, getProto);
     current->add(createThis);
 
     return createThis;
 }
 
 JSObject *
 IonBuilder::getSingletonPrototype(JSFunction *target)
 {
@@ -3889,20 +3889,17 @@ IonBuilder::createThisScriptedSingleton(
     RootedObject templateObject(cx, js_CreateThisForFunctionWithProto(cx, target, proto));
     if (!templateObject)
         return NULL;
 
     // Trigger recompilation if the templateObject changes.
     if (templateObject->type()->newScript)
         types::HeapTypeSet::WatchObjectStateChange(cx, templateObject->type());
 
-    MConstant *protoDef = MConstant::New(ObjectValue(*proto));
-    current->add(protoDef);
-
-    MCreateThis *createThis = MCreateThis::New(callee, protoDef, templateObject);
+    MCreateThisWithTemplate *createThis = MCreateThisWithTemplate::New(templateObject);
     current->add(createThis);
 
     return createThis;
 }
 
 MDefinition *
 IonBuilder::createThis(HandleFunction target, MDefinition *callee)
 {
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -279,16 +279,26 @@ class MacroAssembler : public MacroAssem
         // perform an aligned 32-bit load and adjust the bitmask accordingly.
         JS_STATIC_ASSERT(offsetof(JSFunction, nargs) % sizeof(uint32_t) == 0);
         JS_STATIC_ASSERT(offsetof(JSFunction, flags) == offsetof(JSFunction, nargs) + 2);
         JS_STATIC_ASSERT(IS_LITTLE_ENDIAN);
         Address address(fun, offsetof(JSFunction, nargs));
         uint32_t bit = JSFunction::INTERPRETED << 16;
         branchTest32(Assembler::Zero, address, Imm32(bit), label);
     }
+    void branchIfInterpreted(Register fun, Label *label) {
+        // 16-bit loads are slow and unaligned 32-bit loads may be too so
+        // perform an aligned 32-bit load and adjust the bitmask accordingly.
+        JS_STATIC_ASSERT(offsetof(JSFunction, nargs) % sizeof(uint32_t) == 0);
+        JS_STATIC_ASSERT(offsetof(JSFunction, flags) == offsetof(JSFunction, nargs) + 2);
+        JS_STATIC_ASSERT(IS_LITTLE_ENDIAN);
+        Address address(fun, offsetof(JSFunction, nargs));
+        uint32_t bit = JSFunction::INTERPRETED << 16;
+        branchTest32(Assembler::NonZero, address, Imm32(bit), label);
+    }
 
     using MacroAssemblerSpecific::Push;
 
     void Push(jsid id, Register scratchReg) {
         if (JSID_IS_GCTHING(id)) {
             // If we're pushing a gcthing, then we can't just push the tagged jsid
             // value since the GC won't have any idea that the push instruction
             // carries a reference to a gcthing.  Need to unpack the pointer,
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -415,36 +415,60 @@ class LToIdV : public LCallInstructionHe
 
     MToId *mir() const {
         return mir_->toToId();
     }
 };
 
 // Allocate an object for |new| on the caller-side.
 // Always performs object initialization with a fast path.
-class LCreateThis : public LInstructionHelper<1, 0, 0>
+class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 0>
 {
   public:
-    LIR_HEADER(CreateThis)
-
-    LCreateThis()
+    LIR_HEADER(CreateThisWithTemplate)
+
+    LCreateThisWithTemplate()
     { }
 
+    MCreateThisWithTemplate *mir() const {
+        return mir_->toCreateThisWithTemplate();
+    }
+};
+
+// Allocate an object for |new| on the caller-side, when there is no templateObject.
+class LCreateThisV : public LCallInstructionHelper<BOX_PIECES, 2, 0>
+{
+  public:
+    LIR_HEADER(CreateThisV)
+
+    LCreateThisV(const LAllocation &callee, const LAllocation &prototype)
+    {
+        setOperand(0, callee);
+        setOperand(1, prototype);
+    }
+
+    const LAllocation *getCallee() {
+        return getOperand(0);
+    }
+    const LAllocation *getPrototype() {
+        return getOperand(1);
+    }
+
     MCreateThis *mir() const {
         return mir_->toCreateThis();
     }
 };
 
 // Allocate an object for |new| on the caller-side, when there is no templateObject.
-class LCreateThisVM : public LCallInstructionHelper<1, 2, 0>
+class LCreateThisO : public LCallInstructionHelper<1, 2, 0>
 {
   public:
-    LIR_HEADER(CreateThisVM)
-
-    LCreateThisVM(const LAllocation &callee, const LAllocation &prototype)
+    LIR_HEADER(CreateThisO)
+
+    LCreateThisO(const LAllocation &callee, const LAllocation &prototype)
     {
         setOperand(0, callee);
         setOperand(1, prototype);
     }
 
     const LAllocation *getCallee() {
         return getOperand(0);
     }
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -34,18 +34,19 @@
     _(DefVar)                       \
     _(CallKnown)                    \
     _(CallGeneric)                  \
     _(CallNative)                   \
     _(CallConstructor)              \
     _(ApplyArgsGeneric)             \
     _(StackArgT)                    \
     _(StackArgV)                    \
-    _(CreateThis)                   \
-    _(CreateThisVM)                 \
+    _(CreateThisV)                  \
+    _(CreateThisO)                  \
+    _(CreateThisWithTemplate)       \
     _(ReturnFromCtor)               \
     _(BitNotI)                      \
     _(BitNotV)                      \
     _(BitOpI)                       \
     _(BitOpV)                       \
     _(ShiftI)                       \
     _(UrshD)                        \
     _(Return)                       \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -231,27 +231,34 @@ LIRGenerator::visitPassArg(MPassArg *arg
 
     // Known types can move constant types and/or payloads.
     LStackArgT *stack = new LStackArgT(argslot, useRegisterOrConstant(opd));
     stack->setMir(arg);
     return add(stack);
 }
 
 bool
+LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
+{
+    LCreateThisWithTemplate *lir = new LCreateThisWithTemplate();
+    return define(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitCreateThis(MCreateThis *ins)
 {
-    // Template objects permit fast initialization.
-    if (ins->hasTemplateObject()) {
-        LCreateThis *lir = new LCreateThis();
-        return define(lir, ins) && assignSafepoint(lir, ins);
+    if (ins->needNativeCheck()) {
+        JS_ASSERT(ins->type() == MIRType_Value);
+        LCreateThisV *lir = new LCreateThisV(useRegisterAtStart(ins->getCallee()),
+                                             useRegisterOrConstantAtStart(ins->getPrototype()));
+        return defineReturn(lir, ins) && assignSafepoint(lir, ins);
     }
 
-    LCreateThisVM *lir = new LCreateThisVM(useRegisterOrConstantAtStart(ins->getCallee()),
-                                           useRegisterOrConstantAtStart(ins->getPrototype()));
-
+    LCreateThisO *lir = new LCreateThisO(useRegisterOrConstantAtStart(ins->getCallee()),
+                                         useRegisterOrConstantAtStart(ins->getPrototype()));
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitReturnFromCtor(MReturnFromCtor *ins)
 {
     LReturnFromCtor *lir = new LReturnFromCtor(useRegister(ins->getObject()));
     if (!useBox(lir, LReturnFromCtor::ValueIndex, ins->getValue()))
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -84,16 +84,17 @@ class LIRGenerator : public LIRGenerator
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitInitProp(MInitProp *ins);
     bool visitCheckOverRecursed(MCheckOverRecursed *ins);
     bool visitDefVar(MDefVar *ins);
     bool visitPrepareCall(MPrepareCall *ins);
     bool visitPassArg(MPassArg *arg);
+    bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
     bool visitCreateThis(MCreateThis *ins);
     bool visitReturnFromCtor(MReturnFromCtor *ins);
     bool visitCall(MCall *call);
     bool visitApplyArgs(MApplyArgs *apply);
     bool visitTest(MTest *test);
     bool visitPolyInlineDispatch(MPolyInlineDispatch *ins);
     bool visitCompare(MCompare *comp);
     bool visitTypeOf(MTypeOf *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1566,52 +1566,84 @@ class MGuardString
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Caller-side allocation of |this| for |new|:
+// Given a templateobject, construct |this| for JSOP_NEW
+class MCreateThisWithTemplate
+  : public MNullaryInstruction
+{
+    // Template for |this|, provided by TI
+    CompilerRootObject templateObject_;
+
+    MCreateThisWithTemplate(JSObject *templateObject)
+      : templateObject_(templateObject)
+    {
+        setResultType(MIRType_Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CreateThisWithTemplate);
+    static MCreateThisWithTemplate *New(JSObject *templateObject)
+    {
+        return new MCreateThisWithTemplate(templateObject);
+    }
+    JSObject *getTemplateObject() const {
+        return templateObject_;
+    }
+
+    // Although creation of |this| modifies global state, it is safely repeatable.
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
+// Caller-side allocation of |this| for |new|:
 // Given a prototype operand, construct |this| for JSOP_NEW.
 // For native constructors, returns MagicValue(JS_IS_CONSTRUCTING).
 class MCreateThis
   : public MAryInstruction<2>,
     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
 {
-    // Template for |this|, provided by TI, or NULL.
-    CompilerRootObject templateObject_;
-
-    MCreateThis(MDefinition *callee, MDefinition *prototype, JSObject *templateObject)
-      : templateObject_(templateObject)
+    bool needNativeCheck_;
+
+    MCreateThis(MDefinition *callee, MDefinition *prototype)
+      : needNativeCheck_(true)
     {
         initOperand(0, callee);
         initOperand(1, prototype);
-        setResultType(MIRType_Object);
+
+        // Type is mostly object, except for native constructors
+        // therefore the need of Value type.
+        setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(CreateThis)
-    static MCreateThis *New(MDefinition *callee, MDefinition *prototype, JSObject *templateObject)
+    static MCreateThis *New(MDefinition *callee, MDefinition *prototype)
     {
-        return new MCreateThis(callee, prototype, templateObject);
+        return new MCreateThis(callee, prototype);
     }
 
     MDefinition *getCallee() const {
         return getOperand(0);
     }
     MDefinition *getPrototype() const {
         return getOperand(1);
     }
-    bool hasTemplateObject() const {
-        return !!templateObject_;
-    }
-    JSObject *getTemplateObject() const {
-        JS_ASSERT(hasTemplateObject());
-        return templateObject_;
+    void removeNativeCheck() {
+        needNativeCheck_ = false;
+        setResultType(MIRType_Object);
+    }
+    bool needNativeCheck() const {
+        return needNativeCheck_;
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     TypePolicy *typePolicy() {
         return this;
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -25,16 +25,17 @@ namespace ion {
     _(Beta)                                                                 \
     _(OsrValue)                                                             \
     _(OsrScopeChain)                                                        \
     _(ReturnFromCtor)                                                       \
     _(CheckOverRecursed)                                                    \
     _(RecompileCheck)                                                       \
     _(DefVar)                                                               \
     _(CreateThis)                                                           \
+    _(CreateThisWithTemplate)                                               \
     _(PrepareCall)                                                          \
     _(PassArg)                                                              \
     _(Call)                                                                 \
     _(ApplyArgs)                                                            \
     _(BitNot)                                                               \
     _(TypeOf)                                                               \
     _(ToId)                                                                 \
     _(BitAnd)                                                               \