mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Bug 1166711 part 2.4 - MObjectState: Add support for encoding unboxed objects. r=bhackett
This commit is contained in:
parent
50ea72309c
commit
dcd3b38ebb
@ -3929,20 +3929,75 @@ MCreateThisWithTemplate::canRecoverOnBailout() const
|
||||
return true;
|
||||
}
|
||||
|
||||
MObjectState::MObjectState(MDefinition* obj)
|
||||
bool
|
||||
OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
|
||||
{
|
||||
const UnboxedLayout& layout =
|
||||
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
|
||||
|
||||
// 0 is used as an error code.
|
||||
const UnboxedLayout::PropertyVector& properties = layout.properties();
|
||||
MOZ_ASSERT(properties.length() < 255);
|
||||
|
||||
// Allocate an array of indexes, where the top of each field correspond to
|
||||
// the index of the operand in the MObjectState instance.
|
||||
if (!map.init(alloc, layout.size()))
|
||||
return false;
|
||||
|
||||
// Reset all indexes to 0, which is an error code.
|
||||
for (size_t i = 0; i < map.length(); i++)
|
||||
map[i] = 0;
|
||||
|
||||
// Map the property offsets to the indexes of MObjectState operands.
|
||||
uint8_t index = 1;
|
||||
for (size_t i = 0; i < properties.length(); i++, index++)
|
||||
map[properties[i].offset] = index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MObjectState::MObjectState(MObjectState* state)
|
||||
: numSlots_(state->numSlots_),
|
||||
numFixedSlots_(state->numFixedSlots_),
|
||||
operandIndex_(state->operandIndex_)
|
||||
{
|
||||
// This instruction is only used as a summary for bailout paths.
|
||||
setResultType(MIRType_Object);
|
||||
setRecoveredOnBailout();
|
||||
NativeObject* templateObject = nullptr;
|
||||
}
|
||||
|
||||
MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex)
|
||||
{
|
||||
// This instruction is only used as a summary for bailout paths.
|
||||
setResultType(MIRType_Object);
|
||||
setRecoveredOnBailout();
|
||||
|
||||
if (templateObject->is<NativeObject>()) {
|
||||
NativeObject* nativeObject = &templateObject->as<NativeObject>();
|
||||
numSlots_ = nativeObject->slotSpan();
|
||||
numFixedSlots_ = nativeObject->numFixedSlots();
|
||||
} else {
|
||||
const UnboxedLayout& layout =
|
||||
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
|
||||
// Same as UnboxedLayout::makeNativeGroup
|
||||
numSlots_ = layout.properties().length();
|
||||
numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind());
|
||||
}
|
||||
|
||||
operandIndex_ = operandIndex;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MObjectState::templateObjectOf(MDefinition* obj)
|
||||
{
|
||||
if (obj->isNewObject())
|
||||
templateObject = &obj->toNewObject()->templateObject()->as<PlainObject>();
|
||||
return obj->toNewObject()->templateObject();
|
||||
else if (obj->isCreateThisWithTemplate())
|
||||
templateObject = &obj->toCreateThisWithTemplate()->templateObject()->as<PlainObject>();
|
||||
return obj->toCreateThisWithTemplate()->templateObject();
|
||||
else
|
||||
templateObject = obj->toNewCallObject()->templateObject();
|
||||
numSlots_ = templateObject->slotSpan();
|
||||
numFixedSlots_ = templateObject->numFixedSlots();
|
||||
return obj->toNewCallObject()->templateObject();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3958,7 +4013,17 @@ MObjectState::init(TempAllocator& alloc, MDefinition* obj)
|
||||
MObjectState*
|
||||
MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal)
|
||||
{
|
||||
MObjectState* res = new(alloc) MObjectState(obj);
|
||||
JSObject* templateObject = templateObjectOf(obj);
|
||||
MOZ_ASSERT(templateObject, "Unexpected object creation.");
|
||||
|
||||
OperandIndexMap* operandIndex = nullptr;
|
||||
if (templateObject->is<UnboxedPlainObject>()) {
|
||||
operandIndex = new(alloc) OperandIndexMap;
|
||||
if (!operandIndex || !operandIndex->init(alloc, templateObject))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
|
||||
if (!res || !res->init(alloc, obj))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < res->numSlots(); i++)
|
||||
@ -3969,9 +4034,8 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefined
|
||||
MObjectState*
|
||||
MObjectState::Copy(TempAllocator& alloc, MObjectState* state)
|
||||
{
|
||||
MDefinition* obj = state->object();
|
||||
MObjectState* res = new(alloc) MObjectState(obj);
|
||||
if (!res || !res->init(alloc, obj))
|
||||
MObjectState* res = new(alloc) MObjectState(state);
|
||||
if (!res || !res->init(alloc, state->object()))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < res->numSlots(); i++)
|
||||
res->initSlot(i, state->getSlot(i));
|
||||
|
@ -3359,6 +3359,18 @@ class MNewDerivedTypedObject
|
||||
}
|
||||
};
|
||||
|
||||
// This vector is used when the recovered object is kept unboxed. We map the
|
||||
// offset of each property to the index of the corresponding operands in the
|
||||
// object state.
|
||||
struct OperandIndexMap : public TempObject
|
||||
{
|
||||
// The number of properties is limited by scalar replacement. Thus we cannot
|
||||
// have any large number of properties.
|
||||
FixedList<uint8_t> map;
|
||||
|
||||
bool init(TempAllocator& alloc, JSObject* templateObject);
|
||||
};
|
||||
|
||||
// Represent the content of all slots of an object. This instruction is not
|
||||
// lowered and is not used to generate code.
|
||||
class MObjectState
|
||||
@ -3367,9 +3379,15 @@ class MObjectState
|
||||
{
|
||||
private:
|
||||
uint32_t numSlots_;
|
||||
uint32_t numFixedSlots_;
|
||||
uint32_t numFixedSlots_; // valid if isUnboxed() == false.
|
||||
OperandIndexMap* operandIndex_; // valid if isUnboxed() == true.
|
||||
|
||||
explicit MObjectState(MDefinition* obj);
|
||||
bool isUnboxed() const {
|
||||
return operandIndex_ != nullptr;
|
||||
}
|
||||
|
||||
MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex);
|
||||
explicit MObjectState(MObjectState* state);
|
||||
|
||||
bool init(TempAllocator& alloc, MDefinition* obj);
|
||||
|
||||
@ -3380,6 +3398,10 @@ class MObjectState
|
||||
public:
|
||||
INSTRUCTION_HEADER(ObjectState)
|
||||
|
||||
// Return the template object of any object creation which can be recovered
|
||||
// on bailout.
|
||||
static JSObject* templateObjectOf(MDefinition* obj);
|
||||
|
||||
static MObjectState* New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal);
|
||||
static MObjectState* Copy(TempAllocator& alloc, MObjectState* state);
|
||||
|
||||
@ -3388,6 +3410,7 @@ class MObjectState
|
||||
}
|
||||
|
||||
size_t numFixedSlots() const {
|
||||
MOZ_ASSERT(!isUnboxed());
|
||||
return numFixedSlots_;
|
||||
}
|
||||
size_t numSlots() const {
|
||||
@ -3423,6 +3446,18 @@ class MObjectState
|
||||
setSlot(slot + numFixedSlots(), def);
|
||||
}
|
||||
|
||||
// Interface reserved for unboxed objects.
|
||||
bool hasOffset(uint32_t offset) const {
|
||||
MOZ_ASSERT(isUnboxed());
|
||||
return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0;
|
||||
}
|
||||
MDefinition* getOffset(uint32_t offset) const {
|
||||
return getOperand(operandIndex_->map[offset]);
|
||||
}
|
||||
void setOffset(uint32_t offset, MDefinition* def) {
|
||||
replaceOperand(operandIndex_->map[offset], def);
|
||||
}
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter& writer) const override;
|
||||
bool canRecoverOnBailout() const override {
|
||||
return true;
|
||||
|
@ -1369,13 +1369,30 @@ RObjectState::RObjectState(CompactBufferReader& reader)
|
||||
bool
|
||||
RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||
{
|
||||
RootedNativeObject object(cx, &iter.read().toObject().as<NativeObject>());
|
||||
MOZ_ASSERT(object->slotSpan() == numSlots());
|
||||
|
||||
RootedObject object(cx, &iter.read().toObject());
|
||||
RootedValue val(cx);
|
||||
for (size_t i = 0; i < numSlots(); i++) {
|
||||
val = iter.read();
|
||||
object->setSlot(i, val);
|
||||
|
||||
if (object->is<UnboxedPlainObject>()) {
|
||||
const UnboxedLayout& layout = object->as<UnboxedPlainObject>().layout();
|
||||
|
||||
const UnboxedLayout::PropertyVector& properties = layout.properties();
|
||||
for (size_t i = 0; i < properties.length(); i++) {
|
||||
val = iter.read();
|
||||
// This is the default placeholder value of MObjectState, when no
|
||||
// properties are defined yet.
|
||||
if (val.isUndefined())
|
||||
continue;
|
||||
|
||||
MOZ_ALWAYS_TRUE(object->as<UnboxedPlainObject>().setValue(cx, properties[i], val));
|
||||
}
|
||||
} else {
|
||||
RootedNativeObject nativeObject(cx, &object->as<NativeObject>());
|
||||
MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
|
||||
|
||||
for (size_t i = 0; i < numSlots(); i++) {
|
||||
val = iter.read();
|
||||
nativeObject->setSlot(i, val);
|
||||
}
|
||||
}
|
||||
|
||||
val.setObject(*object);
|
||||
|
@ -145,27 +145,15 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
|
||||
JitSpewDef(JitSpew_Escape, "Check object\n", ins);
|
||||
JitSpewIndent spewIndent(JitSpew_Escape);
|
||||
|
||||
JSObject* obj = nullptr;
|
||||
if (ins->isNewObject())
|
||||
obj = ins->toNewObject()->templateObject();
|
||||
else if (ins->isCreateThisWithTemplate())
|
||||
obj = ins->toCreateThisWithTemplate()->templateObject();
|
||||
else if (ins->isNewCallObject())
|
||||
obj = ins->toNewCallObject()->templateObject();
|
||||
else
|
||||
obj = objDefault;
|
||||
JSObject* obj = objDefault;
|
||||
if (!obj)
|
||||
obj = MObjectState::templateObjectOf(ins);
|
||||
|
||||
if (!obj) {
|
||||
JitSpew(JitSpew_Escape, "No template object defined.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't optimize unboxed objects, which aren't handled by MObjectState.
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
JitSpew(JitSpew_Escape, "Template object is an unboxed plain object.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the object is escaped. If the object is not the first argument
|
||||
// of either a known Store / Load, then we consider it as escaped. This is a
|
||||
// cheap and conservative escape analysis.
|
||||
|
Loading…
Reference in New Issue
Block a user