Bug 1337763 - Add DenseInHole IC to CacheIR draft
authorTed Campbell <tcampbell@mozilla.com>
Thu, 23 Feb 2017 16:04:48 -0500
changeset 490079 776eda965b7ea1d140650fb12d3be1edcbc2e205
parent 488865 99e6cf0082bc4b4ffb6f3f937ce0bdb16c5c543f
child 547159 5bdc33ce622a79fc011f28c0ab63a948c29078cc
push id46988
push userbmo:tcampbell@mozilla.com
push dateMon, 27 Feb 2017 16:58:48 +0000
bugs1337763
milestone54.0a1
Bug 1337763 - Add DenseInHole IC to CacheIR MozReview-Commit-ID: KsHopYVLeb
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
@@ -1769,16 +1769,40 @@ InIRGenerator::tryAttachDenseIn(uint32_t
     writer.loadDenseElementExistsResult(objId, indexId);
     writer.returnFromIC();
 
     trackAttached("DenseIn");
     return true;
 }
 
 bool
+InIRGenerator::tryAttachDenseInHole(uint32_t index, Int32OperandId indexId,
+                                    HandleObject obj, ObjOperandId objId)
+{
+    if (!obj->isNative())
+        return false;
+
+    if (obj->as<NativeObject>().containsDenseElement(index))
+        return false;
+
+    if (!CanAttachDenseElementHole(obj))
+        return false;
+
+    // Guard on the shape, to prevent non-dense elements from appearing.
+    writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
+
+    GeneratePrototypeHoleGuards(writer, obj, objId);
+    writer.loadDenseElementHoleExistsResult(objId, indexId);
+    writer.returnFromIC();
+
+    trackAttached("DenseInHole");
+    return true;
+}
+
+bool
 InIRGenerator::tryAttachNativeIn(HandleId key, ValOperandId keyId,
                                  HandleObject obj, ObjOperandId objId)
 {
     PropertyResult prop;
     JSObject* holder;
     if (!LookupPropertyPure(cx_, obj, key, &holder, &prop))
         return false;
 
@@ -1843,16 +1867,18 @@ InIRGenerator::tryAttachStub()
         return false;
     }
 
     uint32_t index;
     Int32OperandId indexId;
     if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) {
         if (tryAttachDenseIn(index, indexId, obj_, objId))
             return true;
+        if (tryAttachDenseInHole(index, indexId, obj_, objId))
+            return true;
 
         trackNotAttached();
         return false;
     }
 
     trackNotAttached();
     return false;
 }
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -204,16 +204,17 @@ extern const char* CacheKindNames[];
     /* The *Result ops load a value into the cache's result register. */ \
     _(LoadFixedSlotResult)                \
     _(LoadDynamicSlotResult)              \
     _(LoadUnboxedPropertyResult)          \
     _(LoadTypedObjectResult)              \
     _(LoadDenseElementResult)             \
     _(LoadDenseElementHoleResult)         \
     _(LoadDenseElementExistsResult)       \
+    _(LoadDenseElementHoleExistsResult)   \
     _(LoadUnboxedArrayElementResult)      \
     _(LoadTypedElementResult)             \
     _(LoadInt32ArrayLengthResult)         \
     _(LoadUnboxedArrayLengthResult)       \
     _(LoadArgumentsObjectArgResult)       \
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadFunctionLengthResult)           \
     _(LoadStringCharResult)               \
@@ -796,16 +797,20 @@ class MOZ_RAII CacheIRWriter : public JS
     void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj);
         writeOperandId(index);
     }
     void loadDenseElementExistsResult(ObjOperandId obj, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::LoadDenseElementExistsResult, obj);
         writeOperandId(index);
     }
+    void loadDenseElementHoleExistsResult(ObjOperandId obj, Int32OperandId index) {
+        writeOpWithOperandId(CacheOp::LoadDenseElementHoleExistsResult, obj);
+        writeOperandId(index);
+    }
     void loadUnboxedArrayElementResult(ObjOperandId obj, Int32OperandId index, JSValueType elementType) {
         writeOpWithOperandId(CacheOp::LoadUnboxedArrayElementResult, obj);
         writeOperandId(index);
         buffer_.writeByte(uint32_t(elementType));
     }
     void loadTypedElementResult(ObjOperandId obj, Int32OperandId index, TypedThingLayout layout,
                                 Scalar::Type elementType) {
         writeOpWithOperandId(CacheOp::LoadTypedElementResult, obj);
@@ -1163,16 +1168,18 @@ class MOZ_RAII SetPropIRGenerator : publ
 // InIRGenerator generates CacheIR for a In IC.
 class MOZ_RAII InIRGenerator : public IRGenerator
 {
     HandleValue key_;
     HandleObject obj_;
 
     bool tryAttachDenseIn(uint32_t index, Int32OperandId indexId,
                           HandleObject obj, ObjOperandId objId);
+    bool tryAttachDenseInHole(uint32_t index, Int32OperandId indexId,
+                              HandleObject obj, ObjOperandId objId);
     bool tryAttachNativeIn(HandleId key, ValOperandId keyId,
                            HandleObject obj, ObjOperandId objId);
     bool tryAttachNativeInDoesNotExist(HandleId key, ValOperandId keyId,
                                        HandleObject obj, ObjOperandId objId);
 
     void trackAttached(const char* name);
     void trackNotAttached();
 
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1811,16 +1811,54 @@ CacheIRCompiler::emitLoadDenseElementExi
     // Hole check.
     BaseObjectElementIndex element(scratch, index);
     masm.branchTestMagic(Assembler::Equal, element, failure->label());
     masm.moveValue(BooleanValue(true), output.valueReg());
     return true;
 }
 
 bool
+CacheIRCompiler::emitLoadDenseElementHoleExistsResult()
+{
+    AutoOutputRegister output(*this);
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    Register index = allocator.useRegister(masm, reader.int32OperandId());
+    AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    // Make sure the index is nonnegative.
+    masm.branch32(Assembler::LessThan, index, Imm32(0), failure->label());
+
+    // Load obj->elements.
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
+
+    // Guard on the initialized length.
+    Label hole;
+    Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
+    masm.branch32(Assembler::BelowOrEqual, initLength, index, &hole);
+
+    // Load value and replace with true.
+    Label done;
+    masm.loadValue(BaseObjectElementIndex(scratch, index), output.valueReg());
+    masm.branchTestMagic(Assembler::Equal, output.valueReg(), &hole);
+    masm.moveValue(BooleanValue(true), output.valueReg());
+    masm.jump(&done);
+
+    // Load false for the hole.
+    masm.bind(&hole);
+    masm.moveValue(BooleanValue(false), output.valueReg());
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
 CacheIRCompiler::emitLoadUnboxedArrayElementResult()
 {
     AutoOutputRegister output(*this);
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Register index = allocator.useRegister(masm, reader.int32OperandId());
     JSValueType elementType = reader.valueType();
     AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
 
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -43,16 +43,17 @@ namespace jit {
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadFunctionLengthResult)           \
     _(LoadStringLengthResult)             \
     _(LoadStringCharResult)               \
     _(LoadArgumentsObjectArgResult)       \
     _(LoadDenseElementResult)             \
     _(LoadDenseElementHoleResult)         \
     _(LoadDenseElementExistsResult)       \
+    _(LoadDenseElementHoleExistsResult)   \
     _(LoadUnboxedArrayElementResult)      \
     _(LoadTypedElementResult)             \
     _(WrapResult)
 
 // Represents a Value on the Baseline frame's expression stack. Slot 0 is the
 // value on top of the stack (the most recently pushed value), slot 1 is the
 // value pushed before that, etc.
 class BaselineFrameSlot