Bug 1166711 part 2.4 - MObjectState: Add support for encoding unboxed objects. r=bhackett

This commit is contained in:
Nicolas B. Pierron 2015-06-11 14:30:33 +02:00
parent 50ea72309c
commit dcd3b38ebb
4 changed files with 138 additions and 34 deletions

View File

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

View File

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

View File

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

View File

@ -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.