Bug 1175976: IonMonkey - Part2: Get the UnaryArith stub working in ionmonkey, r=jandem
authorHannes Verschore <hv1989@gmail.com>
Fri, 21 Aug 2015 10:14:24 +0200
changeset 287051 bb070785cc9b5fe060217af2a600ad7f10e63258
parent 287050 0f06efef9c6d626de9d1071c038f89ef9a9088d6
child 287052 07e73fa84838415bd184d5685e2efce47d24b988
push id4648
push userdmitchell@mozilla.com
push dateFri, 21 Aug 2015 16:07:49 +0000
reviewersjandem
bugs1175976
milestone43.0a1
Bug 1175976: IonMonkey - Part2: Get the UnaryArith stub working in ionmonkey, r=jandem
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineICList.h
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/SharedIC.cpp
js/src/jit/SharedIC.h
js/src/jit/SharedICList.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1623,17 +1623,17 @@ BaselineCompiler::emitBinaryArith()
 
 bool
 BaselineCompiler::emitUnaryArith()
 {
     // Keep top stack value in R0.
     frame.popRegsAndSync(1);
 
     // Call IC
-    ICUnaryArith_Fallback::Compiler stubCompiler(cx);
+    ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     // Mark R0 as pushed stack value.
     frame.push(R0);
     return true;
 }
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/BaselineIC.h"
 
-#include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/TemplateLib.h"
 
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "builtin/Eval.h"
@@ -37,17 +36,16 @@
 #include "jit/JitFrames-inl.h"
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
-using mozilla::BitwiseCast;
 using mozilla::DebugOnly;
 
 namespace js {
 namespace jit {
 
 static void
 GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
                     Register object, Register scratch,
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -44,20 +44,16 @@ namespace jit {
     _(ToBool_Int32)                              \
     _(ToBool_String)                             \
     _(ToBool_NullUndefined)                      \
     _(ToBool_Double)                             \
     _(ToBool_Object)                             \
                                                  \
     _(ToNumber_Fallback)                         \
                                                  \
-    _(UnaryArith_Fallback)                       \
-    _(UnaryArith_Int32)                          \
-    _(UnaryArith_Double)                         \
-                                                 \
     _(Call_Fallback)                             \
     _(Call_Scripted)                             \
     _(Call_AnyScripted)                          \
     _(Call_Native)                               \
     _(Call_ClassHook)                            \
     _(Call_ScriptedApplyArray)                   \
     _(Call_ScriptedApplyArguments)               \
     _(Call_ScriptedFunCall)                      \
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1724,16 +1724,20 @@ CodeGenerator::visitBinarySharedStub(LBi
     }
 }
 
 void
 CodeGenerator::visitUnarySharedStub(LUnarySharedStub* lir)
 {
     JSOp jsop = JSOp(*lir->mir()->resumePoint()->pc());
     switch (jsop) {
+      case JSOP_BITNOT:
+      case JSOP_NEG:
+        emitSharedStub(ICStub::Kind::UnaryArith_Fallback, lir);
+        break;
       default:
         MOZ_CRASH("Unsupported jsop in shared stubs.");
     }
 }
 
 typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
 static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
 
@@ -7864,16 +7868,21 @@ CodeGenerator::linkSharedStubs(JSContext
         ICStub *stub = nullptr;
 
         switch (sharedStubs_[i].kind) {
           case ICStub::Kind::BinaryArith_Fallback: {
             ICBinaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey);
             stub = stubCompiler.getStub(&stubSpace_);
             break;
           }
+          case ICStub::Kind::UnaryArith_Fallback: {
+            ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey);
+            stub = stubCompiler.getStub(&stubSpace_);
+            break;
+          }
           default:
             MOZ_CRASH("Unsupported shared stub.");
         }
 
         if (!stub)
             return false;
 
         sharedStubs_[i].entry.setFirstStub(stub);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4480,28 +4480,58 @@ IonBuilder::processThrow()
 bool
 IonBuilder::pushConstant(const Value& v)
 {
     current->push(constant(v));
     return true;
 }
 
 bool
+IonBuilder::bitnotTrySpecialized(bool* emitted, MDefinition* input)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    // Try to emit a specialized bitnot instruction based on the input type
+    // of the operand.
+
+    if (input->mightBeType(MIRType_Object) || input->mightBeType(MIRType_Symbol))
+        return true;
+
+    MBitNot* ins = MBitNot::New(alloc(), input);
+    ins->setSpecialization(MIRType_Int32);
+
+    current->add(ins);
+    current->push(ins);
+
+    *emitted = true;
+    return true;
+}
+
+bool
 IonBuilder::jsop_bitnot()
 {
+    bool emitted = false;
+
     MDefinition* input = current->pop();
+
+    if (!forceInlineCaches()) {
+        if (!bitnotTrySpecialized(&emitted, input) || emitted)
+            return emitted;
+    }
+
+    if (!arithTrySharedStub(&emitted, JSOP_BITNOT, nullptr, input) || emitted)
+        return emitted;
+
+    // Not possible to optimize. Do a slow vm call.
     MBitNot* ins = MBitNot::New(alloc(), input);
 
     current->add(ins);
-    ins->infer();
-
     current->push(ins);
-    if (ins->isEffectful() && !resumeAfter(ins))
-        return false;
-    return true;
+    MOZ_ASSERT(ins->isEffectful());
+    return resumeAfter(ins);
 }
 bool
 IonBuilder::jsop_bitop(JSOp op)
 {
     // Pop inputs.
     MDefinition* right = current->pop();
     MDefinition* left = current->pop();
 
@@ -4667,31 +4697,52 @@ IonBuilder::binaryArithTrySpecializedOnB
     if (!maybeInsertResume())
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
-IonBuilder::binaryArithTrySharedStub(bool* emitted, JSOp op,
-                                     MDefinition* left, MDefinition* right)
+IonBuilder::arithTrySharedStub(bool* emitted, JSOp op,
+                               MDefinition* left, MDefinition* right)
 {
     MOZ_ASSERT(*emitted == false);
+    JSOp actualOp = JSOp(*pc);
 
     // Try to emit a shared stub cache.
 
     if (js_JitOptions.disableSharedStubs)
         return true;
 
-    // It is not possible for shared stubs to impersonate another op.
-    if (JSOp(*pc) != op)
-        return true;
-
-    MBinarySharedStub *stub = MBinarySharedStub::New(alloc(), left, right);
+    // The actual jsop 'jsop_pos' is not supported yet.
+    if (actualOp == JSOP_POS)
+        return true;
+
+    MInstruction* stub = nullptr;
+    switch (actualOp) {
+      case JSOP_NEG:
+      case JSOP_BITNOT:
+        MOZ_ASSERT_IF(op == JSOP_MUL, left->isConstantValue() &&
+                                      left->constantValue().toInt32() == -1);
+        MOZ_ASSERT_IF(op != JSOP_MUL, !left);
+
+        stub = MUnarySharedStub::New(alloc(), right);
+        break;
+      case JSOP_ADD:
+      case JSOP_SUB:
+      case JSOP_MUL:
+      case JSOP_DIV:
+      case JSOP_MOD:
+        stub = MBinarySharedStub::New(alloc(), left, right);
+        break;
+      default:
+        MOZ_CRASH("unsupported arith");
+    }
+
     current->add(stub);
     current->push(stub);
 
     // Decrease type from 'any type' to 'empty type' when one of the operands
     // is 'empty typed'.
     maybeMarkEmpty(stub);
 
     if (!resumeAfter(stub))
@@ -4712,17 +4763,17 @@ IonBuilder::jsop_binary_arith(JSOp op, M
 
         if (!binaryArithTrySpecialized(&emitted, op, left, right) || emitted)
             return emitted;
 
         if (!binaryArithTrySpecializedOnBaselineInspector(&emitted, op, left, right) || emitted)
             return emitted;
     }
 
-    if (!binaryArithTrySharedStub(&emitted, op, left, right) || emitted)
+    if (!arithTrySharedStub(&emitted, op, left, right) || emitted)
         return emitted;
 
     // Not possible to optimize. Do a slow vm call.
     MDefinition::Opcode def_op = JSOpToMDefinition(op);
     MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right);
 
     // Decrease type from 'any type' to 'empty type' when one of the operands
     // is 'empty typed'.
@@ -4786,19 +4837,17 @@ IonBuilder::jsop_neg()
 {
     // Since JSOP_NEG does not use a slot, we cannot push the MConstant.
     // The MConstant is therefore passed to JSOP_MUL without slot traffic.
     MConstant* negator = MConstant::New(alloc(), Int32Value(-1));
     current->add(negator);
 
     MDefinition* right = current->pop();
 
-    if (!jsop_binary_arith(JSOP_MUL, negator, right))
-        return false;
-    return true;
+    return jsop_binary_arith(JSOP_MUL, negator, right);
 }
 
 class AutoAccumulateReturns
 {
     MIRGraph& graph_;
     MIRGraphReturns* prev_;
 
   public:
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -484,17 +484,20 @@ class IonBuilder
                          bool barrier, TemporaryTypeSet* objTypes);
 
     // jsop_binary_arith helpers.
     MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right);
     bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
     bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
     bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
                                                       MDefinition* right);
-    bool binaryArithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
+    bool arithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
+
+    // jsop_bitnot helpers.
+    bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
 
     // binary data lookup helpers.
     TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
     TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
     bool typedObjectHasField(MDefinition* typedObj,
                              PropertyName* name,
                              size_t* fieldOffset,
                              TypedObjectPrediction* fieldTypeReprs,
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1993,25 +1993,16 @@ void
 MCall::addArg(size_t argnum, MDefinition* arg)
 {
     // The operand vector is initialized in reverse order by the IonBuilder.
     // It cannot be checked for consistency until all arguments are added.
     // FixedList doesn't initialize its elements, so do an unchecked init.
     initOperand(argnum + NumNonArgumentOperands, arg);
 }
 
-void
-MBitNot::infer()
-{
-    if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(0)->mightBeType(MIRType_Symbol))
-        specialization_ = MIRType_None;
-    else
-        specialization_ = MIRType_Int32;
-}
-
 static inline bool
 IsConstant(MDefinition* def, double v)
 {
     if (!def->isConstant())
         return false;
 
     return NumbersAreIdentical(def->toConstant()->value().toNumber(), v);
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5210,27 +5210,31 @@ class MToObjectOrNull :
 class MBitNot
   : public MUnaryInstruction,
     public BitwisePolicy::Data
 {
   protected:
     explicit MBitNot(MDefinition* input)
       : MUnaryInstruction(input)
     {
+        specialization_ = MIRType_None;
         setResultType(MIRType_Int32);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(BitNot)
     static MBitNot* New(TempAllocator& alloc, MDefinition* input);
     static MBitNot* NewAsmJS(TempAllocator& alloc, MDefinition* input);
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
-    void infer();
+    void setSpecialization(MIRType type) {
+        specialization_ = type;
+        setResultType(type);
+    }
 
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         if (specialization_ == MIRType_None)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/SharedIC.h"
+
+#include "mozilla/Casting.h"
 #include "mozilla/SizePrintfMacros.h"
 
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineIC.h"
 #include "jit/JitSpewer.h"
@@ -19,16 +21,18 @@
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 #include "vm/Interpreter.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/Interpreter-inl.h"
 
+using mozilla::BitwiseCast;
+
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 void
 FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
 {
     if (JitSpewEnabled(JitSpew_BaselineICFallback)) {
@@ -1430,20 +1434,22 @@ ICBinaryArith_DoubleWithInt32::Compiler:
 //
 // UnaryArith_Fallback
 //
 
 static bool
 DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* stub_,
                      HandleValue val, MutableHandleValue res)
 {
+    ICStubCompiler::Engine engine = SharedStubEngine(frame);
+    RootedScript script(cx, SharedStubScript(frame, stub_));
+
     // This fallback stub may trigger debug mode toggling.
-    DebugModeOSRVolatileStub<ICUnaryArith_Fallback*> stub(frame, stub_);
+    DebugModeOSRVolatileStub<ICUnaryArith_Fallback*> stub(engine, frame, stub_);
 
-    RootedScript script(cx, frame->script());
     jsbytecode* pc = stub->icEntry()->pc(script);
     JSOp op = JSOp(*pc);
     FallbackICSpew(cx, stub, "UnaryArith(%s)", js_CodeName[op]);
 
     switch (op) {
       case JSOP_BITNOT: {
         int32_t result;
         if (!BitNot(cx, val, &result))
@@ -1468,31 +1474,31 @@ DoUnaryArithFallback(JSContext* cx, Base
 
     if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard/replace stubs.
         return true;
     }
 
     if (val.isInt32() && res.isInt32()) {
         JitSpew(JitSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
-        ICUnaryArith_Int32::Compiler compiler(cx, op);
+        ICUnaryArith_Int32::Compiler compiler(cx, op, engine);
         ICStub* int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
         stub->addNewStub(int32Stub);
         return true;
     }
 
     if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) {
         JitSpew(JitSpew_BaselineIC, "  Generating %s(Number => Number) stub", js_CodeName[op]);
 
         // Unlink int32 stubs, the double stub handles both cases and TI specializes for both.
         stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32);
 
-        ICUnaryArith_Double::Compiler compiler(cx, op);
+        ICUnaryArith_Double::Compiler compiler(cx, op, engine);
         ICStub* doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
         stub->addNewStub(doubleStub);
         return true;
     }
 
     return true;
@@ -1501,17 +1507,16 @@ DoUnaryArithFallback(JSContext* cx, Base
 typedef bool (*DoUnaryArithFallbackFn)(JSContext*, BaselineFrame*, ICUnaryArith_Fallback*,
                                        HandleValue, MutableHandleValue);
 static const VMFunction DoUnaryArithFallbackInfo =
     FunctionInfo<DoUnaryArithFallbackFn>(DoUnaryArithFallback, TailCall, PopValues(1));
 
 bool
 ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
 {
-    MOZ_ASSERT(engine_ == Engine::Baseline);
     MOZ_ASSERT(R0 == JSReturnOperand);
 
     // Restore the tail call register.
     EmitRestoreTailCallReg(masm);
 
     // Ensure stack is fully synced for the expression decompiler.
     masm.pushValue(R0);
 
@@ -1521,18 +1526,16 @@ ICUnaryArith_Fallback::Compiler::generat
     pushFramePtr(masm, R0.scratchReg());
 
     return tailCallVM(DoUnaryArithFallbackInfo, masm);
 }
 
 bool
 ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
 {
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
     Label failure;
     masm.ensureDouble(R0, FloatReg0, &failure);
 
     MOZ_ASSERT(op == JSOP_NEG || op == JSOP_BITNOT);
 
     if (op == JSOP_NEG) {
         masm.negateDouble(FloatReg0);
         masm.boxDouble(FloatReg0, R0);
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -1414,18 +1414,18 @@ class ICUnaryArith_Fallback : public ICF
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler& masm);
 
       public:
-        explicit Compiler(JSContext* cx)
-          : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, Engine::Baseline)
+        explicit Compiler(JSContext* cx, Engine engine)
+          : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, engine)
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICUnaryArith_Fallback>(space, getStubCode());
         }
     };
 };
 
@@ -1438,18 +1438,18 @@ class ICUnaryArith_Int32 : public ICStub
     {}
 
   public:
     class Compiler : public ICMultiStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler& masm);
 
       public:
-        Compiler(JSContext* cx, JSOp op)
-          : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, Engine::Baseline)
+        Compiler(JSContext* cx, JSOp op, Engine engine)
+          : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, engine)
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICUnaryArith_Int32>(space, getStubCode());
         }
     };
 };
 
@@ -1462,18 +1462,18 @@ class ICUnaryArith_Double : public ICStu
     {}
 
   public:
     class Compiler : public ICMultiStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler& masm);
 
       public:
-        Compiler(JSContext* cx, JSOp op)
-          : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, Engine::Baseline)
+        Compiler(JSContext* cx, JSOp op, Engine engine)
+          : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, engine)
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICUnaryArith_Double>(space, getStubCode());
         }
     };
 };
 
--- a/js/src/jit/SharedICList.h
+++ b/js/src/jit/SharedICList.h
@@ -15,13 +15,16 @@ namespace jit {
     _(BinaryArith_Fallback)                      \
     _(BinaryArith_Int32)                         \
     _(BinaryArith_Double)                        \
     _(BinaryArith_StringConcat)                  \
     _(BinaryArith_StringObjectConcat)            \
     _(BinaryArith_BooleanWithInt32)              \
     _(BinaryArith_DoubleWithInt32)               \
                                                  \
+    _(UnaryArith_Fallback)                       \
+    _(UnaryArith_Int32)                          \
+    _(UnaryArith_Double)                         \
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_SharedICList_h */