зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1323037 - CacheIR for dense elements with holes. r=jandem
This commit is contained in:
Родитель
b79dc7d5f9
Коммит
fb5eec602f
|
@ -1711,6 +1711,60 @@ BaselineCacheIRCompiler::emitLoadDenseElementResult()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardNoDenseElements()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
// Load obj->elements.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
|
||||
// Make sure there are no dense elements.
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::NotEqual, initLength, Imm32(0), failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadDenseElementHoleResult()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
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 the value.
|
||||
Label done;
|
||||
masm.loadValue(BaseObjectElementIndex(scratch, index), R0);
|
||||
masm.branchTestMagic(Assembler::NotEqual, R0, &done);
|
||||
|
||||
// Load undefined for the hole.
|
||||
masm.bind(&hole);
|
||||
masm.moveValue(UndefinedValue(), R0);
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadUnboxedArrayElementResult()
|
||||
{
|
||||
|
|
|
@ -96,6 +96,8 @@ GetPropIRGenerator::tryAttachStub()
|
|||
ValOperandId indexId = getElemKeyValueId();
|
||||
if (tryAttachDenseElement(obj, objId, indexId))
|
||||
return true;
|
||||
if (tryAttachDenseElementHole(obj, objId, indexId))
|
||||
return true;
|
||||
if (tryAttachUnboxedArrayElement(obj, objId, indexId))
|
||||
return true;
|
||||
if (tryAttachArgumentsObjectArg(obj, objId, indexId))
|
||||
|
@ -908,6 +910,88 @@ GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CanAttachDenseElementHole(JSObject* obj)
|
||||
{
|
||||
// Make sure this object already has dense elements.
|
||||
if (obj->as<NativeObject>().getDenseInitializedLength() == 0)
|
||||
return false;
|
||||
|
||||
// Now we have to make sure the objects on the prototype don't
|
||||
// have any int32 properties or that such properties can't appear
|
||||
// without a shape change.
|
||||
// Otherwise returning undefined for holes would obviously be incorrect,
|
||||
// because we would have to lookup a property on the prototype instead.
|
||||
do {
|
||||
if (obj->isIndexed())
|
||||
return false;
|
||||
|
||||
if (ClassCanHaveExtraProperties(obj->getClass()))
|
||||
return false;
|
||||
|
||||
JSObject* proto = obj->staticPrototype();
|
||||
if (!proto)
|
||||
break;
|
||||
|
||||
if (!proto->isNative())
|
||||
return false;
|
||||
|
||||
// Make sure objects on the prototype don't have dense elements.
|
||||
if (proto->as<NativeObject>().getDenseInitializedLength() != 0)
|
||||
return false;
|
||||
|
||||
obj = proto;
|
||||
} while (true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId,
|
||||
ValOperandId indexId)
|
||||
{
|
||||
MOZ_ASSERT(idVal_.isInt32());
|
||||
|
||||
if (idVal_.toInt32() < 0)
|
||||
return false;
|
||||
|
||||
if (!obj->isNative() || !CanAttachDenseElementHole(obj))
|
||||
return false;
|
||||
|
||||
// Guard on the shape, to prevent non-dense elements from appearing.
|
||||
writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
|
||||
|
||||
if (obj->hasUncacheableProto()) {
|
||||
// If the shape does not imply the proto, emit an explicit proto guard.
|
||||
writer.guardProto(objId, obj->staticPrototype());
|
||||
}
|
||||
|
||||
JSObject* pobj = obj->staticPrototype();
|
||||
while (pobj) {
|
||||
ObjOperandId protoId = writer.loadObject(pobj);
|
||||
|
||||
// Non-singletons with uncacheable protos can change their proto
|
||||
// without a shape change, so also guard on the group (which determines
|
||||
// the proto) in this case.
|
||||
if (pobj->hasUncacheableProto() && !pobj->isSingleton())
|
||||
writer.guardGroup(protoId, pobj->group());
|
||||
|
||||
// Make sure the shape matches, to avoid non-dense elements or anything
|
||||
// else that is being checked by CanAttachDenseElementHole.
|
||||
writer.guardShape(protoId, pobj->as<NativeObject>().lastProperty());
|
||||
|
||||
// Also make sure there are no dense elements.
|
||||
writer.guardNoDenseElements(protoId);
|
||||
|
||||
pobj = pobj->staticPrototype();
|
||||
}
|
||||
|
||||
Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
|
||||
writer.loadDenseElementHoleResult(objId, int32IndexId);
|
||||
writer.typeMonitorResult();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachUnboxedArrayElement(HandleObject obj, ObjOperandId objId,
|
||||
ValOperandId indexId)
|
||||
|
|
|
@ -145,6 +145,7 @@ enum class CacheKind : uint8_t
|
|||
_(GuardNoDetachedTypedObjects) \
|
||||
_(GuardMagicValue) \
|
||||
_(GuardFrameHasNoArgumentsObject) \
|
||||
_(GuardNoDenseElements) \
|
||||
_(GuardNoUnboxedExpando) \
|
||||
_(GuardAndLoadUnboxedExpando) \
|
||||
_(LoadObject) \
|
||||
|
@ -160,6 +161,7 @@ enum class CacheKind : uint8_t
|
|||
_(LoadUnboxedPropertyResult) \
|
||||
_(LoadTypedObjectResult) \
|
||||
_(LoadDenseElementResult) \
|
||||
_(LoadDenseElementHoleResult) \
|
||||
_(LoadUnboxedArrayElementResult) \
|
||||
_(LoadTypedElementResult) \
|
||||
_(LoadInt32ArrayLengthResult) \
|
||||
|
@ -450,6 +452,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
void loadFrameArgumentResult(Int32OperandId index) {
|
||||
writeOpWithOperandId(CacheOp::LoadFrameArgumentResult, index);
|
||||
}
|
||||
void guardNoDenseElements(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardNoDenseElements, obj);
|
||||
}
|
||||
void guardNoUnboxedExpando(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
|
||||
}
|
||||
|
@ -534,6 +539,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
writeOpWithOperandId(CacheOp::LoadDenseElementResult, obj);
|
||||
writeOperandId(index);
|
||||
}
|
||||
void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) {
|
||||
writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj);
|
||||
writeOperandId(index);
|
||||
}
|
||||
void loadUnboxedArrayElementResult(ObjOperandId obj, Int32OperandId index, JSValueType elementType) {
|
||||
writeOpWithOperandId(CacheOp::LoadUnboxedArrayElementResult, obj);
|
||||
writeOperandId(index);
|
||||
|
@ -682,6 +691,7 @@ class MOZ_RAII GetPropIRGenerator
|
|||
bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
|
||||
|
||||
bool tryAttachDenseElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
|
||||
bool tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
|
||||
bool tryAttachUnboxedArrayElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
|
||||
bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче