Bug 1341261: [Part 4] Compare Undefined/Null+Object r=tcampbell
authorMatthew Gaudet <mgaudet@mozilla.com>
Tue, 05 Jun 2018 13:13:37 -0400
changeset 486352 b3455cc95ec0d3112993b3ebff49b1dadff7d715
parent 486351 24cdf8f1b8af8f174bff62f0360ac6f9528762af
child 486353 2d21ae32eca79970dd918da9686fb14359b7f5ac
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1341261
milestone63.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 1341261: [Part 4] Compare Undefined/Null+Object r=tcampbell
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -4853,16 +4853,38 @@ CompareIRGenerator::tryAttachNumber(ValO
     writer.compareDoubleResult(op_, lhsId, rhsId);
     writer.returnFromIC();
 
     trackAttached("Number");
     return true;
 }
 
 bool
+CompareIRGenerator::tryAttachObjectUndefined(ValOperandId lhsId, ValOperandId rhsId)
+{
+    if (!(lhsVal_.isNullOrUndefined() && rhsVal_.isObject()) &&
+        !(rhsVal_.isNullOrUndefined() && lhsVal_.isObject()))
+        return false;
+
+    if (op_ != JSOP_EQ && op_ != JSOP_NE)
+        return false;
+
+    ValOperandId obj = rhsVal_.isObject() ? rhsId : lhsId;
+    ValOperandId undefOrNull = rhsVal_.isObject() ? lhsId : rhsId;
+
+    writer.guardIsNullOrUndefined(undefOrNull);
+    ObjOperandId objOperand = writer.guardIsObject(obj);
+    writer.compareObjectUndefinedNullResult(op_, objOperand);
+    writer.returnFromIC();
+
+    trackAttached("ObjectUndefined");
+    return true;
+}
+
+bool
 CompareIRGenerator::tryAttachStub()
 {
     MOZ_ASSERT(cacheKind_ == CacheKind::Compare);
     MOZ_ASSERT(IsEqualityOp(op_) ||
                op_ == JSOP_LE || op_ == JSOP_LT ||
                op_ == JSOP_GE || op_ == JSOP_GT);
 
     AutoAssertNoPendingException aanpe(cx_);
@@ -4872,16 +4894,18 @@ CompareIRGenerator::tryAttachStub()
 
     if (IsEqualityOp(op_)) {
         if (tryAttachString(lhsId, rhsId))
             return true;
         if (tryAttachObject(lhsId, rhsId))
             return true;
         if (tryAttachSymbol(lhsId, rhsId))
             return true;
+        if (tryAttachObjectUndefined(lhsId, rhsId))
+            return true;
         if (tryAttachStrictDifferentTypes(lhsId, rhsId))
             return true;
     }
 
     // We want these to come below to allow us to bypass the
     // strictly-different-types cases in the below attachment code
     if (tryAttachInt32(lhsId, rhsId))
         return true;
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -177,16 +177,19 @@ enum class CacheKind : uint8_t
 };
 
 extern const char* CacheKindNames[];
 
 #define CACHE_IR_OPS(_)                   \
     _(GuardIsObject)                      \
     _(GuardIsObjectOrNull)                \
     _(GuardIsNullOrUndefined)             \
+    _(GuardIsNotNullOrUndefined)          \
+    _(GuardIsNull)                        \
+    _(GuardIsUndefined)                   \
     _(GuardIsBoolean)                     \
     _(GuardIsString)                      \
     _(GuardIsSymbol)                      \
     _(GuardIsNumber)                      \
     _(GuardIsInt32)                       \
     _(GuardIsInt32Index)                  \
     _(GuardType)                          \
     _(GuardShape)                         \
@@ -321,16 +324,17 @@ extern const char* CacheKindNames[];
     _(CallStringConcatResult)             \
     _(CallStringObjectConcatResult)       \
                                           \
     _(CompareStringResult)                \
     _(CompareObjectResult)                \
     _(CompareSymbolResult)                \
     _(CompareInt32Result)                 \
     _(CompareDoubleResult)                \
+    _(CompareObjectUndefinedNullResult)   \
                                           \
     _(CallPrintString)                    \
     _(Breakpoint)                         \
                                           \
     _(TypeMonitorResult)                  \
     _(ReturnFromIC)                       \
     _(WrapResult)
 
@@ -597,16 +601,25 @@ class MOZ_RAII CacheIRWriter : public JS
         buffer_.writeByte(uint32_t(type));
     }
     void guardIsObjectOrNull(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsObjectOrNull, val);
     }
     void guardIsNullOrUndefined(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsNullOrUndefined, val);
     }
+    void guardIsNotNullOrUndefined(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::GuardIsNotNullOrUndefined, val);
+    }
+    void guardIsNull(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::GuardIsNull, val);
+    }
+    void guardIsUndefined(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::GuardIsUndefined, val);
+    }
     void guardShape(ObjOperandId obj, Shape* shape) {
         MOZ_ASSERT(shape);
         writeOpWithOperandId(CacheOp::GuardShape, obj);
         addStubField(uintptr_t(shape), StubField::Type::Shape);
     }
     void guardShapeForClass(ObjOperandId obj, Shape* shape) {
         // Guard shape to ensure that object class is unchanged. This is true
         // for all shapes.
@@ -1254,16 +1267,20 @@ class MOZ_RAII CacheIRWriter : public JS
         writeOperandId(rhs);
         buffer_.writeByte(uint32_t(op));
     }
     void compareObjectResult(uint32_t op, ObjOperandId lhs, ObjOperandId rhs) {
         writeOpWithOperandId(CacheOp::CompareObjectResult, lhs);
         writeOperandId(rhs);
         buffer_.writeByte(uint32_t(op));
     }
+    void compareObjectUndefinedNullResult(uint32_t op, ObjOperandId object) {
+        writeOpWithOperandId(CacheOp::CompareObjectUndefinedNullResult, object);
+        buffer_.writeByte(uint32_t(op));
+    }
     void compareSymbolResult(uint32_t op, SymbolOperandId lhs, SymbolOperandId rhs) {
         writeOpWithOperandId(CacheOp::CompareSymbolResult, lhs);
         writeOperandId(rhs);
         buffer_.writeByte(uint32_t(op));
     }
     void compareInt32Result(uint32_t op, Int32OperandId lhs, Int32OperandId rhs) {
         writeOpWithOperandId(CacheOp::CompareInt32Result, lhs);
         writeOperandId(rhs);
@@ -1825,16 +1842,18 @@ class MOZ_RAII CompareIRGenerator : publ
     HandleValue rhsVal_;
 
     bool tryAttachString(ValOperandId lhsId, ValOperandId rhsId);
     bool tryAttachObject(ValOperandId lhsId, ValOperandId rhsId);
     bool tryAttachSymbol(ValOperandId lhsId, ValOperandId rhsId);
     bool tryAttachStrictDifferentTypes(ValOperandId lhsId, ValOperandId rhsId);
     bool tryAttachInt32(ValOperandId lhsId, ValOperandId rhsId);
     bool tryAttachNumber(ValOperandId lhsId, ValOperandId rhsId);
+    bool tryAttachNumberUndefined(ValOperandId lhsId, ValOperandId rhsId);
+    bool tryAttachObjectUndefined(ValOperandId lhsId, ValOperandId rhsId);
 
     void trackAttached(const char* name);
 
   public:
     CompareIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
                        JSOp op, HandleValue lhsVal, HandleValue rhsVal);
 
     bool tryAttachStub();
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1372,16 +1372,73 @@ CacheIRCompiler::emitGuardIsNullOrUndefi
     Label success;
     masm.branchTestNull(Assembler::Equal, input, &success);
     masm.branchTestUndefined(Assembler::NotEqual, input, failure->label());
 
     masm.bind(&success);
     return true;
 }
 
+
+bool
+CacheIRCompiler::emitGuardIsNotNullOrUndefined()
+{
+    ValOperandId inputId = reader.valOperandId();
+    JSValueType knownType = allocator.knownType(inputId);
+    if (knownType == JSVAL_TYPE_UNDEFINED || knownType == JSVAL_TYPE_NULL)
+        return false;
+
+    ValueOperand input = allocator.useValueRegister(masm, inputId);
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTestNull(Assembler::Equal, input, failure->label());
+    masm.branchTestUndefined(Assembler::Equal, input, failure->label());
+
+    return true;
+}
+
+
+bool
+CacheIRCompiler::emitGuardIsNull()
+{
+    ValOperandId inputId = reader.valOperandId();
+    JSValueType knownType = allocator.knownType(inputId);
+    if (knownType == JSVAL_TYPE_NULL)
+        return true;
+
+    ValueOperand input = allocator.useValueRegister(masm, inputId);
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    Label success;
+    masm.branchTestNull(Assembler::NotEqual, input, failure->label());
+    return true;
+}
+
+bool
+CacheIRCompiler::emitGuardIsUndefined()
+{
+    ValOperandId inputId = reader.valOperandId();
+    JSValueType knownType = allocator.knownType(inputId);
+    if (knownType == JSVAL_TYPE_UNDEFINED)
+        return true;
+
+    ValueOperand input = allocator.useValueRegister(masm, inputId);
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTestUndefined(Assembler::NotEqual, input, failure->label());
+    return true;
+}
+
+
 bool
 CacheIRCompiler::emitGuardIsObjectOrNull()
 {
     ValOperandId inputId = reader.valOperandId();
     JSValueType knownType = allocator.knownType(inputId);
     if (knownType == JSVAL_TYPE_OBJECT || knownType == JSVAL_TYPE_NULL)
         return true;
 
@@ -3132,16 +3189,45 @@ CacheIRCompiler::emitCompareDoubleResult
 
     masm.bind(&ifTrue);
     masm.moveValue(BooleanValue(true), output.valueReg());
     masm.bind(&done);
     return true;
 }
 
 bool
+CacheIRCompiler::emitCompareObjectUndefinedNullResult()
+{
+    AutoOutputRegister output(*this);
+
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    JSOp op = reader.jsop();
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
+        // obj !== undefined/null for all objects.
+        masm.moveValue(BooleanValue(op == JSOP_STRICTNE), output.valueReg());
+    } else {
+        MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE);
+        AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
+        Label done, emulatesUndefined;
+        masm.branchIfObjectEmulatesUndefined(obj, scratch, failure->label(), &emulatesUndefined);
+        masm.moveValue(BooleanValue(op == JSOP_NE), output.valueReg());
+        masm.jump(&done);
+        masm.bind(&emulatesUndefined);
+        masm.moveValue(BooleanValue(op == JSOP_EQ), output.valueReg());
+        masm.bind(&done);
+    }
+    return true;
+}
+
+bool
 CacheIRCompiler::emitCallPrintString()
 {
     const char* str = reinterpret_cast<char*>(reader.pointer());
     masm.printf(str);
     return true;
 }
 
 bool
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -14,16 +14,19 @@
 namespace js {
 namespace jit {
 
 // The ops below are defined in CacheIRCompiler and codegen is shared between
 // BaselineCacheIRCompiler and IonCacheIRCompiler.
 #define CACHE_IR_SHARED_OPS(_)            \
     _(GuardIsObject)                      \
     _(GuardIsNullOrUndefined)             \
+    _(GuardIsNotNullOrUndefined)          \
+    _(GuardIsNull)                        \
+    _(GuardIsUndefined)                   \
     _(GuardIsObjectOrNull)                \
     _(GuardIsBoolean)                     \
     _(GuardIsString)                      \
     _(GuardIsSymbol)                      \
     _(GuardIsNumber)                      \
     _(GuardIsInt32)                       \
     _(GuardIsInt32Index)                  \
     _(GuardType)                          \
@@ -90,16 +93,17 @@ namespace jit {
     _(LoadInt32TruthyResult)              \
     _(LoadDoubleTruthyResult)             \
     _(LoadStringTruthyResult)             \
     _(LoadObjectTruthyResult)             \
     _(CompareObjectResult)                \
     _(CompareSymbolResult)                \
     _(CompareInt32Result)                 \
     _(CompareDoubleResult)                \
+    _(CompareObjectUndefinedNullResult)   \
     _(ArrayJoinResult)                    \
     _(CallPrintString)                    \
     _(Breakpoint)                         \
     _(MegamorphicLoadSlotResult)          \
     _(MegamorphicLoadSlotByValueResult)   \
     _(MegamorphicStoreSlot)               \
     _(MegamorphicHasPropResult)           \
     _(CallObjectHasSparseElementResult)   \