Bug 1337763 - Add DenseInHole IC to CacheIR
MozReview-Commit-ID: KsHopYVLeb
--- 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