Bug 1323037 - CacheIR for dense elements with holes. r=jandem

This commit is contained in:
Tom Schuster 2016-12-15 19:06:13 +01:00
Родитель b79dc7d5f9
Коммит fb5eec602f
3 изменённых файлов: 148 добавлений и 0 удалений

Просмотреть файл

@ -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);