Introduce ObjectAccess, which is used by LoadNamedField and StoreNamedField to denote what parts of an object are referred to by a given load or store. Refactor HGraphBuilder to use ObjectAccess, which removes the need to manually set GVN flags and simplifies the code as well.
Review URL: https://codereview.chromium.org/14284010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14791 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
1d39355405
commit
94b4240f5c
@ -369,8 +369,7 @@ void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
|
||||
|
||||
void LStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(*String::cast(*name())->ToCString());
|
||||
hydrogen()->access().PrintTo(stream);
|
||||
stream->Add(" <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
@ -358,7 +358,6 @@ Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
HValue* undefined = graph()->GetConstantUndefined();
|
||||
|
||||
HInstruction* boilerplate =
|
||||
@ -387,20 +386,13 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
|
||||
flags = static_cast<HAllocate::Flags>(
|
||||
flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
|
||||
}
|
||||
HInstruction* object =
|
||||
AddInstruction(new(zone) HAllocate(context(),
|
||||
size_in_bytes,
|
||||
HType::JSObject(),
|
||||
flags));
|
||||
|
||||
HInstruction* object = AddInstruction(new(zone)
|
||||
HAllocate(context(), size_in_bytes, HType::JSObject(), flags));
|
||||
|
||||
for (int i = 0; i < size; i += kPointerSize) {
|
||||
HInstruction* value =
|
||||
AddInstruction(new(zone) HLoadNamedField(
|
||||
boilerplate, true, Representation::Tagged(), i));
|
||||
AddInstruction(new(zone) HStoreNamedField(object,
|
||||
factory->empty_string(),
|
||||
value, true,
|
||||
Representation::Tagged(), i));
|
||||
HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
|
||||
AddStore(object, access, AddLoad(boilerplate, access));
|
||||
}
|
||||
|
||||
checker.ElseDeopt();
|
||||
@ -430,11 +422,11 @@ Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
|
||||
|
||||
template<>
|
||||
HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
|
||||
Representation representation = casted_stub()->representation();
|
||||
HInstruction* load = AddInstruction(DoBuildLoadNamedField(
|
||||
GetParameter(0), casted_stub()->is_inobject(),
|
||||
representation, casted_stub()->offset()));
|
||||
return load;
|
||||
HObjectAccess access = casted_stub()->is_inobject() ?
|
||||
HObjectAccess::ForJSObjectOffset(casted_stub()->offset()) :
|
||||
HObjectAccess::ForBackingStoreOffset(casted_stub()->offset());
|
||||
return AddInstruction(BuildLoadNamedField(GetParameter(0), access,
|
||||
casted_stub()->representation()));
|
||||
}
|
||||
|
||||
|
||||
@ -445,11 +437,11 @@ Handle<Code> LoadFieldStub::GenerateCode() {
|
||||
|
||||
template<>
|
||||
HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
|
||||
Representation representation = casted_stub()->representation();
|
||||
HInstruction* load = AddInstruction(DoBuildLoadNamedField(
|
||||
GetParameter(0), casted_stub()->is_inobject(),
|
||||
representation, casted_stub()->offset()));
|
||||
return load;
|
||||
HObjectAccess access = casted_stub()->is_inobject() ?
|
||||
HObjectAccess::ForJSObjectOffset(casted_stub()->offset()) :
|
||||
HObjectAccess::ForBackingStoreOffset(casted_stub()->offset());
|
||||
return AddInstruction(BuildLoadNamedField(GetParameter(0), access,
|
||||
casted_stub()->representation()));
|
||||
}
|
||||
|
||||
|
||||
@ -487,8 +479,8 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
|
||||
AddInstruction(new(zone) HTrapAllocationMemento(js_array));
|
||||
|
||||
HInstruction* array_length =
|
||||
AddInstruction(HLoadNamedField::NewArrayLength(
|
||||
zone, js_array, js_array, HType::Smi()));
|
||||
AddLoad(js_array, HObjectAccess::ForArrayLength());
|
||||
array_length->set_type(HType::Smi());
|
||||
|
||||
ElementsKind to_kind = casted_stub()->to_kind();
|
||||
BuildNewSpaceArrayCheck(array_length, to_kind);
|
||||
@ -514,20 +506,12 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
|
||||
casted_stub()->from_kind(), new_elements,
|
||||
to_kind, array_length, elements_length);
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
|
||||
AddInstruction(new(zone) HStoreNamedField(js_array,
|
||||
factory->elements_field_string(),
|
||||
new_elements, true,
|
||||
Representation::Tagged(),
|
||||
JSArray::kElementsOffset));
|
||||
AddStore(js_array, HObjectAccess::ForElementsPointer(), new_elements);
|
||||
|
||||
if_builder.End();
|
||||
|
||||
AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_string(),
|
||||
map, true,
|
||||
Representation::Tagged(),
|
||||
JSArray::kMapOffset));
|
||||
AddStore(js_array, HObjectAccess::ForMap(), map);
|
||||
|
||||
return js_array;
|
||||
}
|
||||
|
||||
|
@ -2483,7 +2483,7 @@ void HParameter::PrintDataTo(StringStream* stream) {
|
||||
|
||||
void HLoadNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
|
||||
access_.PrintTo(stream);
|
||||
if (HasTypeCheck()) {
|
||||
stream->Add(" ");
|
||||
typecheck()->PrintNameTo(stream);
|
||||
@ -2805,11 +2805,9 @@ void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
|
||||
void HStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(*String::cast(*name())->ToCString());
|
||||
access_.PrintTo(stream);
|
||||
stream->Add(" = ");
|
||||
value()->PrintNameTo(stream);
|
||||
stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
|
||||
if (NeedsWriteBarrier()) {
|
||||
stream->Add(" (write-barrier)");
|
||||
}
|
||||
@ -3669,4 +3667,141 @@ void HCheckFunction::Verify() {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
HObjectAccess HObjectAccess::ForFixedArrayHeader(int offset) {
|
||||
ASSERT(offset >= 0);
|
||||
ASSERT(offset < FixedArray::kHeaderSize);
|
||||
if (offset == FixedArray::kLengthOffset) return ForFixedArrayLength();
|
||||
return HObjectAccess(kInobject, offset);
|
||||
}
|
||||
|
||||
|
||||
HObjectAccess HObjectAccess::ForJSObjectOffset(int offset) {
|
||||
ASSERT(offset >= 0);
|
||||
Portion portion = kInobject;
|
||||
|
||||
if (offset == JSObject::kElementsOffset) {
|
||||
portion = kElementsPointer;
|
||||
} else if (offset == JSObject::kMapOffset) {
|
||||
portion = kMaps;
|
||||
}
|
||||
return HObjectAccess(portion, offset, Handle<String>::null());
|
||||
}
|
||||
|
||||
|
||||
HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) {
|
||||
ASSERT(offset >= 0);
|
||||
Portion portion = kInobject;
|
||||
|
||||
if (offset == JSObject::kElementsOffset) {
|
||||
portion = kElementsPointer;
|
||||
} else if (offset == JSArray::kLengthOffset) {
|
||||
portion = kArrayLengths;
|
||||
} else if (offset == JSObject::kMapOffset) {
|
||||
portion = kMaps;
|
||||
}
|
||||
return HObjectAccess(portion, offset, Handle<String>::null());
|
||||
}
|
||||
|
||||
|
||||
HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset) {
|
||||
ASSERT(offset >= 0);
|
||||
return HObjectAccess(kBackingStore, offset, Handle<String>::null());
|
||||
}
|
||||
|
||||
|
||||
HObjectAccess HObjectAccess::ForField(Handle<Map> map,
|
||||
LookupResult *lookup, Handle<String> name) {
|
||||
ASSERT(lookup->IsField() || lookup->IsTransitionToField(*map));
|
||||
int index;
|
||||
if (lookup->IsField()) {
|
||||
index = lookup->GetLocalFieldIndexFromMap(*map);
|
||||
} else {
|
||||
Map* transition = lookup->GetTransitionMapFromMap(*map);
|
||||
int descriptor = transition->LastAdded();
|
||||
index = transition->instance_descriptors()->GetFieldIndex(descriptor) -
|
||||
map->inobject_properties();
|
||||
}
|
||||
if (index < 0) {
|
||||
// Negative property indices are in-object properties, indexed
|
||||
// from the end of the fixed part of the object.
|
||||
int offset = (index * kPointerSize) + map->instance_size();
|
||||
return HObjectAccess(kInobject, offset);
|
||||
} else {
|
||||
// Non-negative property indices are in the properties array.
|
||||
int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
|
||||
return HObjectAccess(kBackingStore, offset, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HObjectAccess::SetGVNFlags(HValue *instr, bool is_store) {
|
||||
// set the appropriate GVN flags for a given load or store instruction
|
||||
if (is_store) {
|
||||
// track dominating allocations in order to eliminate write barriers
|
||||
instr->SetGVNFlag(kDependsOnNewSpacePromotion);
|
||||
instr->SetFlag(HValue::kTrackSideEffectDominators);
|
||||
instr->SetFlag(HValue::kDeoptimizeOnUndefined);
|
||||
} else {
|
||||
// try to GVN loads, but don't hoist above map changes
|
||||
instr->SetFlag(HValue::kUseGVN);
|
||||
instr->SetGVNFlag(kDependsOnMaps);
|
||||
}
|
||||
|
||||
switch (portion()) {
|
||||
case kArrayLengths:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesArrayLengths : kDependsOnArrayLengths);
|
||||
break;
|
||||
case kInobject:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesInobjectFields : kDependsOnInobjectFields);
|
||||
break;
|
||||
case kDouble:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesDoubleFields : kDependsOnDoubleFields);
|
||||
break;
|
||||
case kBackingStore:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesBackingStoreFields : kDependsOnBackingStoreFields);
|
||||
break;
|
||||
case kElementsPointer:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesElementsPointer : kDependsOnElementsPointer);
|
||||
break;
|
||||
case kMaps:
|
||||
instr->SetGVNFlag(is_store
|
||||
? kChangesMaps : kDependsOnMaps);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HObjectAccess::PrintTo(StringStream* stream) {
|
||||
stream->Add(".");
|
||||
|
||||
switch (portion()) {
|
||||
case kArrayLengths:
|
||||
stream->Add("%length");
|
||||
break;
|
||||
case kElementsPointer:
|
||||
stream->Add("%elements");
|
||||
break;
|
||||
case kMaps:
|
||||
stream->Add("%map");
|
||||
break;
|
||||
case kDouble: // fall through
|
||||
case kInobject:
|
||||
if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
|
||||
stream->Add("[in-object]");
|
||||
break;
|
||||
case kBackingStore:
|
||||
if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
|
||||
stream->Add("[backing-store]");
|
||||
break;
|
||||
}
|
||||
|
||||
stream->Add("@%d", offset());
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -5201,14 +5201,114 @@ class HStoreContextSlot: public HTemplateInstruction<2> {
|
||||
};
|
||||
|
||||
|
||||
// Represents an access to a portion of an object, such as the map pointer,
|
||||
// array elements pointer, etc, but not accesses to array elements themselves.
|
||||
class HObjectAccess {
|
||||
public:
|
||||
inline bool IsInobject() const {
|
||||
return portion() != kBackingStore;
|
||||
}
|
||||
|
||||
inline int offset() const {
|
||||
return OffsetField::decode(value_);
|
||||
}
|
||||
|
||||
inline Handle<String> name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
static HObjectAccess ForHeapNumberValue() {
|
||||
return HObjectAccess(kDouble, HeapNumber::kValueOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForElementsPointer() {
|
||||
return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForArrayLength() {
|
||||
return HObjectAccess(kArrayLengths, JSArray::kLengthOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForFixedArrayLength() {
|
||||
return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForPropertiesPointer() {
|
||||
return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForMap() {
|
||||
return HObjectAccess(kMaps, JSObject::kMapOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForAllocationSitePayload() {
|
||||
return HObjectAccess(kInobject, AllocationSiteInfo::kPayloadOffset);
|
||||
}
|
||||
|
||||
// Create an access to an offset in a fixed array header.
|
||||
static HObjectAccess ForFixedArrayHeader(int offset);
|
||||
|
||||
// Create an access to an in-object property in a JSObject.
|
||||
static HObjectAccess ForJSObjectOffset(int offset);
|
||||
|
||||
// Create an access to an in-object property in a JSArray.
|
||||
static HObjectAccess ForJSArrayOffset(int offset);
|
||||
|
||||
// Create an access to the backing store of an object.
|
||||
static HObjectAccess ForBackingStoreOffset(int offset);
|
||||
|
||||
// Create an access to a resolved field (in-object or backing store).
|
||||
static HObjectAccess ForField(Handle<Map> map,
|
||||
LookupResult *lookup, Handle<String> name = Handle<String>::null());
|
||||
|
||||
void PrintTo(StringStream* stream);
|
||||
|
||||
protected:
|
||||
void SetGVNFlags(HValue *instr, bool is_store);
|
||||
|
||||
private:
|
||||
// internal use only; different parts of an object or array
|
||||
enum Portion {
|
||||
kMaps, // map of an object
|
||||
kArrayLengths, // the length of an array
|
||||
kElementsPointer, // elements pointer
|
||||
kBackingStore, // some field in the backing store
|
||||
kDouble, // some double field
|
||||
kInobject // some other in-object field
|
||||
};
|
||||
|
||||
HObjectAccess(Portion portion, int offset,
|
||||
Handle<String> name = Handle<String>::null())
|
||||
: value_(PortionField::encode(portion) | OffsetField::encode(offset)),
|
||||
name_(name) {
|
||||
ASSERT(this->offset() == offset); // offset should decode correctly
|
||||
ASSERT(this->portion() == portion); // portion should decode correctly
|
||||
}
|
||||
|
||||
class PortionField : public BitField<Portion, 0, 3> {};
|
||||
class OffsetField : public BitField<int, 3, 29> {};
|
||||
|
||||
uint32_t value_; // encodes both portion and offset
|
||||
Handle<String> name_;
|
||||
|
||||
friend class HLoadNamedField;
|
||||
friend class HStoreNamedField;
|
||||
|
||||
inline Portion portion() const {
|
||||
return PortionField::decode(value_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class HLoadNamedField: public HTemplateInstruction<2> {
|
||||
public:
|
||||
HLoadNamedField(HValue* object, bool is_in_object,
|
||||
Representation field_representation,
|
||||
int offset, HValue* typecheck = NULL)
|
||||
: is_in_object_(is_in_object),
|
||||
field_representation_(field_representation),
|
||||
offset_(offset) {
|
||||
HLoadNamedField(HValue* object,
|
||||
HObjectAccess access,
|
||||
HValue* typecheck = NULL,
|
||||
Representation field_representation
|
||||
= Representation::Tagged())
|
||||
: access_(access),
|
||||
field_representation_(field_representation) {
|
||||
ASSERT(object != NULL);
|
||||
SetOperandAt(0, object);
|
||||
SetOperandAt(1, typecheck != NULL ? typecheck : object);
|
||||
@ -5225,31 +5325,7 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
||||
} else {
|
||||
set_representation(Representation::Tagged());
|
||||
}
|
||||
SetFlag(kUseGVN);
|
||||
if (FLAG_track_double_fields && representation().IsDouble()) {
|
||||
ASSERT(is_in_object);
|
||||
ASSERT(offset == HeapNumber::kValueOffset);
|
||||
SetGVNFlag(kDependsOnDoubleFields);
|
||||
} else if (is_in_object) {
|
||||
SetGVNFlag(kDependsOnInobjectFields);
|
||||
SetGVNFlag(kDependsOnMaps);
|
||||
} else {
|
||||
SetGVNFlag(kDependsOnBackingStoreFields);
|
||||
SetGVNFlag(kDependsOnMaps);
|
||||
}
|
||||
}
|
||||
|
||||
static HLoadNamedField* NewArrayLength(Zone* zone, HValue* object,
|
||||
HValue* typecheck,
|
||||
HType type = HType::Tagged()) {
|
||||
Representation representation =
|
||||
type.IsSmi() ? Representation::Smi() : Representation::Tagged();
|
||||
HLoadNamedField* result = new(zone) HLoadNamedField(
|
||||
object, true, representation, JSArray::kLengthOffset, typecheck);
|
||||
result->set_type(type);
|
||||
result->SetGVNFlag(kDependsOnArrayLengths);
|
||||
result->ClearGVNFlag(kDependsOnInobjectFields);
|
||||
return result;
|
||||
access.SetGVNFlags(this, false);
|
||||
}
|
||||
|
||||
HValue* object() { return OperandAt(0); }
|
||||
@ -5259,9 +5335,10 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
||||
}
|
||||
|
||||
bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
|
||||
bool is_in_object() const { return is_in_object_; }
|
||||
HObjectAccess access() const { return access_; }
|
||||
bool is_in_object() const { return access_.IsInobject(); }
|
||||
Representation field_representation() const { return representation_; }
|
||||
int offset() const { return offset_; }
|
||||
int offset() const { return access_.offset(); }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
@ -5273,15 +5350,14 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) {
|
||||
HLoadNamedField* b = HLoadNamedField::cast(other);
|
||||
return is_in_object_ == b->is_in_object_ && offset_ == b->offset_;
|
||||
return is_in_object() == b->is_in_object() && offset() == b->offset();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool IsDeletable() const { return true; }
|
||||
|
||||
bool is_in_object_;
|
||||
HObjectAccess access_;
|
||||
Representation field_representation_;
|
||||
int offset_;
|
||||
};
|
||||
|
||||
|
||||
@ -5578,30 +5654,17 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> {
|
||||
class HStoreNamedField: public HTemplateInstruction<2> {
|
||||
public:
|
||||
HStoreNamedField(HValue* obj,
|
||||
Handle<Name> name,
|
||||
HObjectAccess access,
|
||||
HValue* val,
|
||||
bool in_object,
|
||||
Representation field_representation,
|
||||
int offset)
|
||||
: name_(name),
|
||||
is_in_object_(in_object),
|
||||
Representation field_representation
|
||||
= Representation::Tagged())
|
||||
: access_(access),
|
||||
field_representation_(field_representation),
|
||||
offset_(offset),
|
||||
transition_unique_id_(),
|
||||
new_space_dominator_(NULL) {
|
||||
SetOperandAt(0, obj);
|
||||
SetOperandAt(1, val);
|
||||
SetFlag(kTrackSideEffectDominators);
|
||||
if (FLAG_track_double_fields && field_representation.IsDouble()) {
|
||||
SetGVNFlag(kChangesDoubleFields);
|
||||
} else if (is_in_object_) {
|
||||
SetGVNFlag(kChangesInobjectFields);
|
||||
SetGVNFlag(kDependsOnNewSpacePromotion);
|
||||
} else {
|
||||
SetGVNFlag(kChangesBackingStoreFields);
|
||||
SetGVNFlag(kDependsOnNewSpacePromotion);
|
||||
}
|
||||
SetFlag(kDeoptimizeOnUndefined);
|
||||
access.SetGVNFlags(this, true);
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
|
||||
@ -5625,9 +5688,10 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
||||
HValue* object() { return OperandAt(0); }
|
||||
HValue* value() { return OperandAt(1); }
|
||||
|
||||
Handle<Name> name() const { return name_; }
|
||||
bool is_in_object() const { return is_in_object_; }
|
||||
int offset() const { return offset_; }
|
||||
HObjectAccess access() const { return access_; }
|
||||
Handle<String> name() const { return access_.name(); }
|
||||
bool is_in_object() const { return access_.IsInobject(); }
|
||||
int offset() const { return access_.offset(); }
|
||||
Handle<Map> transition() const { return transition_; }
|
||||
UniqueValueId transition_unique_id() const { return transition_unique_id_; }
|
||||
void set_transition(Handle<Map> map) { transition_ = map; }
|
||||
@ -5656,10 +5720,8 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<Name> name_;
|
||||
bool is_in_object_;
|
||||
HObjectAccess access_;
|
||||
Representation field_representation_;
|
||||
int offset_;
|
||||
Handle<Map> transition_;
|
||||
UniqueValueId transition_unique_id_;
|
||||
HValue* new_space_dominator_;
|
||||
|
479
src/hydrogen.cc
479
src/hydrogen.cc
@ -1195,16 +1195,10 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
|
||||
new_length->AssumeRepresentation(Representation::Integer32());
|
||||
new_length->ClearFlag(HValue::kCanOverflow);
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
Representation representation = IsFastElementsKind(kind)
|
||||
? Representation::Smi() : Representation::Tagged();
|
||||
HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
|
||||
object,
|
||||
factory->length_field_string(),
|
||||
new_length, true,
|
||||
representation,
|
||||
JSArray::kLengthOffset));
|
||||
length_store->SetGVNFlag(kChangesArrayLengths);
|
||||
AddStore(object, HObjectAccess::ForArrayLength(), new_length,
|
||||
representation);
|
||||
}
|
||||
|
||||
length_checker.Else();
|
||||
@ -1286,8 +1280,9 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
|
||||
}
|
||||
HInstruction* length = NULL;
|
||||
if (is_js_array) {
|
||||
length = AddInstruction(
|
||||
HLoadNamedField::NewArrayLength(zone, object, mapcheck, HType::Smi()));
|
||||
length = AddLoad(object, HObjectAccess::ForArrayLength(), mapcheck,
|
||||
Representation::Smi());
|
||||
length->set_type(HType::Smi());
|
||||
} else {
|
||||
length = AddInstruction(new(zone) HFixedArrayBaseLength(elements));
|
||||
}
|
||||
@ -1413,21 +1408,16 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
|
||||
void HGraphBuilder::BuildInitializeElements(HValue* elements,
|
||||
ElementsKind kind,
|
||||
HValue* capacity) {
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<Map> map = IsFastDoubleElementsKind(kind)
|
||||
? factory->fixed_double_array_map()
|
||||
: factory->fixed_array_map();
|
||||
BuildStoreMap(elements, map);
|
||||
|
||||
Handle<String> fixed_array_length_field_name = factory->length_field_string();
|
||||
AddStoreMapConstant(elements, map);
|
||||
Representation representation = IsFastElementsKind(kind)
|
||||
? Representation::Smi() : Representation::Tagged();
|
||||
HInstruction* store_length =
|
||||
new(zone) HStoreNamedField(elements, fixed_array_length_field_name,
|
||||
capacity, true, representation,
|
||||
FixedArray::kLengthOffset);
|
||||
AddInstruction(store_length);
|
||||
AddStore(elements, HObjectAccess::ForFixedArrayLength(), capacity,
|
||||
representation);
|
||||
}
|
||||
|
||||
|
||||
@ -1446,7 +1436,7 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
|
||||
HValue* allocation_site_payload,
|
||||
HValue* length_field) {
|
||||
|
||||
BuildStoreMap(array, array_map);
|
||||
AddStore(array, HObjectAccess::ForMap(), array_map);
|
||||
|
||||
HConstant* empty_fixed_array =
|
||||
new(zone()) HConstant(
|
||||
@ -1454,21 +1444,9 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
|
||||
Representation::Tagged());
|
||||
AddInstruction(empty_fixed_array);
|
||||
|
||||
AddInstruction(new(zone()) HStoreNamedField(array,
|
||||
isolate()->factory()->properties_field_symbol(),
|
||||
empty_fixed_array,
|
||||
true,
|
||||
Representation::Tagged(),
|
||||
JSArray::kPropertiesOffset));
|
||||
|
||||
HInstruction* length_store = AddInstruction(
|
||||
new(zone()) HStoreNamedField(array,
|
||||
isolate()->factory()->length_field_string(),
|
||||
length_field,
|
||||
true,
|
||||
Representation::Tagged(),
|
||||
JSArray::kLengthOffset));
|
||||
length_store->SetGVNFlag(kChangesArrayLengths);
|
||||
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
|
||||
AddStore(array, access, empty_fixed_array);
|
||||
AddStore(array, HObjectAccess::ForArrayLength(), length_field);
|
||||
|
||||
if (mode == TRACK_ALLOCATION_SITE) {
|
||||
BuildCreateAllocationSiteInfo(array,
|
||||
@ -1482,58 +1460,17 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
|
||||
}
|
||||
|
||||
HInnerAllocatedObject* elements = new(zone()) HInnerAllocatedObject(
|
||||
array,
|
||||
elements_location);
|
||||
array, elements_location);
|
||||
AddInstruction(elements);
|
||||
|
||||
HInstruction* elements_store = AddInstruction(
|
||||
new(zone()) HStoreNamedField(
|
||||
array,
|
||||
isolate()->factory()->elements_field_string(),
|
||||
elements,
|
||||
true,
|
||||
Representation::Tagged(),
|
||||
JSArray::kElementsOffset));
|
||||
elements_store->SetGVNFlag(kChangesElementsPointer);
|
||||
|
||||
AddStore(array, HObjectAccess::ForElementsPointer(), elements);
|
||||
return elements;
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
|
||||
HValue* map) {
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<String> map_field_name = factory->map_field_string();
|
||||
HInstruction* store_map =
|
||||
new(zone) HStoreNamedField(object, map_field_name, map,
|
||||
true, Representation::Tagged(),
|
||||
JSObject::kMapOffset);
|
||||
store_map->ClearGVNFlag(kChangesInobjectFields);
|
||||
store_map->SetGVNFlag(kChangesMaps);
|
||||
AddInstruction(store_map);
|
||||
return store_map;
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
|
||||
Handle<Map> map) {
|
||||
Zone* zone = this->zone();
|
||||
HValue* map_constant =
|
||||
AddInstruction(new(zone) HConstant(map, Representation::Tagged()));
|
||||
return BuildStoreMap(object, map_constant);
|
||||
}
|
||||
|
||||
|
||||
HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
|
||||
HValue* typecheck) {
|
||||
HLoadNamedField* instr = new(zone()) HLoadNamedField(object, true,
|
||||
Representation::Tagged(), JSObject::kElementsOffset, typecheck);
|
||||
AddInstruction(instr);
|
||||
instr->SetGVNFlag(kDependsOnElementsPointer);
|
||||
instr->ClearGVNFlag(kDependsOnMaps);
|
||||
instr->ClearGVNFlag(kDependsOnInobjectFields);
|
||||
return instr;
|
||||
HValue* typecheck) {
|
||||
return AddLoad(object, HObjectAccess::ForElementsPointer(), typecheck);
|
||||
}
|
||||
|
||||
|
||||
@ -1586,7 +1523,6 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
||||
ElementsKind kind,
|
||||
HValue* length,
|
||||
HValue* new_capacity) {
|
||||
Zone* zone = this->zone();
|
||||
HValue* context = environment()->LookupContext();
|
||||
|
||||
BuildNewSpaceArrayCheck(new_capacity, kind);
|
||||
@ -1598,13 +1534,7 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
||||
new_elements, kind,
|
||||
length, new_capacity);
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
|
||||
object,
|
||||
factory->elements_field_string(),
|
||||
new_elements, true, Representation::Tagged(),
|
||||
JSArray::kElementsOffset));
|
||||
elements_store->SetGVNFlag(kChangesElementsPointer);
|
||||
AddStore(object, HObjectAccess::ForElementsPointer(), new_elements);
|
||||
|
||||
return new_elements;
|
||||
}
|
||||
@ -1709,7 +1639,6 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
|
||||
ElementsKind kind,
|
||||
int length) {
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
|
||||
NoObservableSideEffectsScope no_effects(this);
|
||||
|
||||
@ -1739,16 +1668,8 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
|
||||
// Copy the JS array part.
|
||||
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
|
||||
if ((i != JSArray::kElementsOffset) || (length == 0)) {
|
||||
HInstruction* value = AddInstruction(new(zone) HLoadNamedField(
|
||||
boilerplate, true, Representation::Tagged(), i));
|
||||
if (i != JSArray::kMapOffset) {
|
||||
AddInstruction(new(zone) HStoreNamedField(object,
|
||||
factory->empty_string(),
|
||||
value, true,
|
||||
Representation::Tagged(), i));
|
||||
} else {
|
||||
BuildStoreMap(object, value);
|
||||
}
|
||||
HObjectAccess access = HObjectAccess::ForJSArrayOffset(i);
|
||||
AddStore(object, access, AddLoad(boilerplate, access));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1763,21 +1684,12 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
|
||||
HValue* boilerplate_elements = AddLoadElements(boilerplate);
|
||||
HValue* object_elements =
|
||||
AddInstruction(new(zone) HInnerAllocatedObject(object, elems_offset));
|
||||
AddInstruction(new(zone) HStoreNamedField(object,
|
||||
factory->elements_field_string(),
|
||||
object_elements, true,
|
||||
Representation::Tagged(),
|
||||
JSObject::kElementsOffset));
|
||||
AddStore(object, HObjectAccess::ForElementsPointer(), object_elements);
|
||||
|
||||
// Copy the elements array header.
|
||||
for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
|
||||
HInstruction* value =
|
||||
AddInstruction(new(zone) HLoadNamedField(
|
||||
boilerplate_elements, true, Representation::Tagged(), i));
|
||||
AddInstruction(new(zone) HStoreNamedField(object_elements,
|
||||
factory->empty_string(),
|
||||
value, true,
|
||||
Representation::Tagged(), i));
|
||||
HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
|
||||
AddStore(object_elements, access, AddLoad(boilerplate_elements, access));
|
||||
}
|
||||
|
||||
// Copy the elements array contents.
|
||||
@ -1857,34 +1769,30 @@ HValue* HGraphBuilder::BuildCreateAllocationSiteInfo(HValue* previous_object,
|
||||
HInnerAllocatedObject(previous_object, previous_object_size);
|
||||
AddInstruction(alloc_site);
|
||||
Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
|
||||
BuildStoreMap(alloc_site, alloc_site_map);
|
||||
AddInstruction(new(zone()) HStoreNamedField(alloc_site,
|
||||
isolate()->factory()->payload_string(),
|
||||
payload,
|
||||
true,
|
||||
Representation::Tagged(),
|
||||
AllocationSiteInfo::kPayloadOffset));
|
||||
AddStoreMapConstant(alloc_site, alloc_site_map);
|
||||
HObjectAccess access = HObjectAccess::ForAllocationSitePayload();
|
||||
AddStore(alloc_site, access, payload);
|
||||
return alloc_site;
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* context) {
|
||||
// Get the global context, then the native context
|
||||
HInstruction* global_object = AddInstruction(new(zone())
|
||||
HGlobalObject(context));
|
||||
HInstruction* native_context = AddInstruction(new(zone())
|
||||
HLoadNamedField(global_object, true, Representation::Tagged(),
|
||||
GlobalObject::kNativeContextOffset));
|
||||
return native_context;
|
||||
HGlobalObject(context));
|
||||
HObjectAccess access = HObjectAccess::ForJSObjectOffset(
|
||||
GlobalObject::kNativeContextOffset);
|
||||
return AddLoad(global_object, access);
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HGraphBuilder::BuildGetArrayFunction(HValue* context) {
|
||||
HInstruction* native_context = BuildGetNativeContext(context);
|
||||
int offset = Context::kHeaderSize +
|
||||
kPointerSize * Context::ARRAY_FUNCTION_INDEX;
|
||||
HInstruction* array_function = AddInstruction(new(zone())
|
||||
HLoadNamedField(native_context, true, Representation::Tagged(), offset));
|
||||
return array_function;
|
||||
HInstruction* index = AddInstruction(new(zone())
|
||||
HConstant(Context::ARRAY_FUNCTION_INDEX, Representation::Integer32()));
|
||||
|
||||
return AddInstruction(new (zone())
|
||||
HLoadKeyed(native_context, index, NULL, FAST_ELEMENTS));
|
||||
}
|
||||
|
||||
|
||||
@ -1905,13 +1813,18 @@ HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
|
||||
|
||||
HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) {
|
||||
HInstruction* native_context = builder()->BuildGetNativeContext(context);
|
||||
int offset = Context::kHeaderSize +
|
||||
kPointerSize * Context::JS_ARRAY_MAPS_INDEX;
|
||||
HInstruction* map_array = AddInstruction(new(zone())
|
||||
HLoadNamedField(native_context, true, Representation::Tagged(), offset));
|
||||
offset = kind_ * kPointerSize + FixedArrayBase::kHeaderSize;
|
||||
return AddInstruction(new(zone()) HLoadNamedField(
|
||||
map_array, true, Representation::Tagged(), offset));
|
||||
|
||||
HInstruction* index = builder()->AddInstruction(new(zone())
|
||||
HConstant(Context::JS_ARRAY_MAPS_INDEX, Representation::Integer32()));
|
||||
|
||||
HInstruction* map_array = builder()->AddInstruction(new(zone())
|
||||
HLoadKeyed(native_context, index, NULL, FAST_ELEMENTS));
|
||||
|
||||
HInstruction* kind_index = builder()->AddInstruction(new(zone())
|
||||
HConstant(kind_, Representation::Integer32()));
|
||||
|
||||
return builder()->AddInstruction(new(zone())
|
||||
HLoadKeyed(map_array, kind_index, NULL, FAST_ELEMENTS));
|
||||
}
|
||||
|
||||
|
||||
@ -2020,6 +1933,39 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
|
||||
}
|
||||
|
||||
|
||||
HStoreNamedField* HGraphBuilder::AddStore(HValue *object,
|
||||
HObjectAccess access,
|
||||
HValue *val,
|
||||
Representation representation) {
|
||||
HStoreNamedField *instr = new(zone())
|
||||
HStoreNamedField(object, access, val, representation);
|
||||
AddInstruction(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
HLoadNamedField* HGraphBuilder::AddLoad(HValue *object,
|
||||
HObjectAccess access,
|
||||
HValue *typecheck,
|
||||
Representation representation) {
|
||||
HLoadNamedField *instr =
|
||||
new(zone()) HLoadNamedField(object, access, typecheck, representation);
|
||||
AddInstruction(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
|
||||
Handle<Map> map) {
|
||||
HValue* constant =
|
||||
AddInstruction(new(zone()) HConstant(map, Representation::Tagged()));
|
||||
HStoreNamedField *instr =
|
||||
new(zone()) HStoreNamedField(object, HObjectAccess::ForMap(), constant);
|
||||
AddInstruction(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
|
||||
TypeFeedbackOracle* oracle)
|
||||
: HGraphBuilder(info),
|
||||
@ -6390,7 +6336,7 @@ static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
|
||||
Code* unoptimized_code, FunctionLiteral* expr) {
|
||||
int start_position = expr->start_position();
|
||||
RelocIterator it(unoptimized_code);
|
||||
for (;!it.done(); it.next()) {
|
||||
for (; !it.done(); it.next()) {
|
||||
RelocInfo* rinfo = it.rinfo();
|
||||
if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
|
||||
Object* obj = rinfo->target_object();
|
||||
@ -7072,20 +7018,6 @@ static bool ComputeLoadStoreField(Handle<Map> type,
|
||||
}
|
||||
|
||||
|
||||
static int ComputeLoadStoreFieldIndex(Handle<Map> type,
|
||||
LookupResult* lookup) {
|
||||
ASSERT(lookup->IsField() || lookup->IsTransitionToField(*type));
|
||||
if (lookup->IsField()) {
|
||||
return lookup->GetLocalFieldIndexFromMap(*type);
|
||||
} else {
|
||||
Map* transition = lookup->GetTransitionMapFromMap(*type);
|
||||
int descriptor = transition->LastAdded();
|
||||
int index = transition->instance_descriptors()->GetFieldIndex(descriptor);
|
||||
return index - type->inobject_properties();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Representation ComputeLoadStoreRepresentation(Handle<Map> type,
|
||||
LookupResult* lookup) {
|
||||
if (lookup->IsField()) {
|
||||
@ -7150,43 +7082,37 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
||||
zone()));
|
||||
}
|
||||
|
||||
int index = ComputeLoadStoreFieldIndex(map, lookup);
|
||||
bool is_in_object = index < 0;
|
||||
HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
|
||||
Representation representation = ComputeLoadStoreRepresentation(map, lookup);
|
||||
int offset = index * kPointerSize;
|
||||
if (index < 0) {
|
||||
// Negative property indices are in-object properties, indexed
|
||||
// from the end of the fixed part of the object.
|
||||
offset += map->instance_size();
|
||||
} else {
|
||||
offset += FixedArray::kHeaderSize;
|
||||
}
|
||||
bool transition_to_field = lookup->IsTransitionToField(*map);
|
||||
|
||||
HStoreNamedField *instr;
|
||||
if (FLAG_track_double_fields && representation.IsDouble()) {
|
||||
if (transition_to_field) {
|
||||
// The store requires a mutable HeapNumber to be allocated.
|
||||
NoObservableSideEffectsScope no_side_effects(this);
|
||||
HInstruction* heap_number_size = AddInstruction(new(zone()) HConstant(
|
||||
HeapNumber::kSize, Representation::Integer32()));
|
||||
HInstruction* double_box = AddInstruction(new(zone()) HAllocate(
|
||||
environment()->LookupContext(), heap_number_size,
|
||||
HType::HeapNumber(), HAllocate::CAN_ALLOCATE_IN_NEW_SPACE));
|
||||
BuildStoreMap(double_box, isolate()->factory()->heap_number_map());
|
||||
AddInstruction(new(zone()) HStoreNamedField(
|
||||
double_box, name, value, true,
|
||||
Representation::Double(), HeapNumber::kValueOffset));
|
||||
value = double_box;
|
||||
representation = Representation::Tagged();
|
||||
AddStoreMapConstant(double_box, isolate()->factory()->heap_number_map());
|
||||
AddStore(double_box, HObjectAccess::ForHeapNumberValue(),
|
||||
value, Representation::Double());
|
||||
instr = new(zone()) HStoreNamedField(object, field_access, double_box);
|
||||
} else {
|
||||
HInstruction* double_box = AddInstruction(new(zone()) HLoadNamedField(
|
||||
object, is_in_object, Representation::Tagged(), offset));
|
||||
// Already holds a HeapNumber; load the box and write its value field.
|
||||
HInstruction* double_box = AddLoad(object, field_access);
|
||||
double_box->set_type(HType::HeapNumber());
|
||||
return new(zone()) HStoreNamedField(
|
||||
double_box, name, value, true,
|
||||
Representation::Double(), HeapNumber::kValueOffset);
|
||||
instr = new(zone()) HStoreNamedField(double_box,
|
||||
HObjectAccess::ForHeapNumberValue(), value, Representation::Double());
|
||||
}
|
||||
} else {
|
||||
// This is a non-double store.
|
||||
instr = new(zone()) HStoreNamedField(
|
||||
object, field_access, value, representation);
|
||||
}
|
||||
HStoreNamedField* instr = new(zone()) HStoreNamedField(
|
||||
object, name, value, is_in_object, representation, offset);
|
||||
|
||||
if (transition_to_field) {
|
||||
Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
|
||||
instr->set_transition(transition);
|
||||
@ -7256,9 +7182,10 @@ bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad(
|
||||
BuildCheckNonSmi(object);
|
||||
|
||||
HInstruction* typecheck =
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
HInstruction* instr =
|
||||
HLoadNamedField::NewArrayLength(zone(), object, typecheck);
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
HInstruction* instr = new(zone())
|
||||
HLoadNamedField(object, HObjectAccess::ForArrayLength(), typecheck);
|
||||
|
||||
instr->set_position(expr->position());
|
||||
ast_context()->ReturnInstruction(instr, expr->id());
|
||||
return true;
|
||||
@ -7278,53 +7205,42 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
|
||||
// Use monomorphic load if property lookup results in the same field index
|
||||
// for all maps. Requires special map check on the set of all handled maps.
|
||||
HInstruction* instr = NULL;
|
||||
if (types->length() > 0 && types->length() <= kMaxLoadPolymorphism) {
|
||||
LookupResult lookup(isolate());
|
||||
int previous_field_offset = 0;
|
||||
bool previous_field_is_in_object = false;
|
||||
Representation representation = Representation::None();
|
||||
int count;
|
||||
for (count = 0; count < types->length(); ++count) {
|
||||
Handle<Map> map = types->at(count);
|
||||
if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
|
||||
LookupResult lookup(isolate());
|
||||
int count;
|
||||
Representation representation = Representation::None();
|
||||
HObjectAccess access = HObjectAccess::ForMap(); // initial value unused.
|
||||
for (count = 0;
|
||||
count < types->length() && count < kMaxLoadPolymorphism;
|
||||
++count) {
|
||||
Handle<Map> map = types->at(count);
|
||||
if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
|
||||
|
||||
int index = ComputeLoadStoreFieldIndex(map, &lookup);
|
||||
Representation new_representation =
|
||||
ComputeLoadStoreRepresentation(map, &lookup);
|
||||
bool is_in_object = index < 0;
|
||||
int offset = index * kPointerSize;
|
||||
HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
|
||||
Representation new_representation =
|
||||
ComputeLoadStoreRepresentation(map, &lookup);
|
||||
|
||||
if (index < 0) {
|
||||
// Negative property indices are in-object properties, indexed
|
||||
// from the end of the fixed part of the object.
|
||||
offset += map->instance_size();
|
||||
} else {
|
||||
offset += FixedArray::kHeaderSize;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
previous_field_offset = offset;
|
||||
previous_field_is_in_object = is_in_object;
|
||||
representation = new_representation;
|
||||
} else if (offset != previous_field_offset ||
|
||||
is_in_object != previous_field_is_in_object ||
|
||||
(FLAG_track_fields &&
|
||||
!representation.IsCompatibleForLoad(new_representation))) {
|
||||
break;
|
||||
}
|
||||
|
||||
representation = representation.generalize(new_representation);
|
||||
}
|
||||
|
||||
if (count == types->length()) {
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
instr = DoBuildLoadNamedField(
|
||||
object, previous_field_is_in_object,
|
||||
representation, previous_field_offset);
|
||||
if (count == 0) {
|
||||
// First time through the loop; set access and representation.
|
||||
access = new_access;
|
||||
representation = new_representation;
|
||||
} else if (!representation.IsCompatibleForLoad(new_representation)) {
|
||||
// Representations did not match.
|
||||
break;
|
||||
} else if (access.offset() != new_access.offset()) {
|
||||
// Offsets did not match.
|
||||
break;
|
||||
} else if (access.IsInobject() != new_access.IsInobject()) {
|
||||
// In-objectness did not match.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr == NULL) {
|
||||
if (count == types->length()) {
|
||||
// Everything matched; can use monomorphic load.
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
instr = BuildLoadNamedField(object, access, representation);
|
||||
} else {
|
||||
// Something did not match; must use a polymorphic load.
|
||||
HValue* context = environment()->LookupContext();
|
||||
instr = new(zone()) HLoadNamedFieldPolymorphic(
|
||||
context, object, types, name, zone());
|
||||
@ -7881,40 +7797,22 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
|
||||
}
|
||||
|
||||
|
||||
HLoadNamedField* HOptimizedGraphBuilder::BuildLoadNamedField(
|
||||
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(
|
||||
HValue* object,
|
||||
Handle<Map> map,
|
||||
LookupResult* lookup) {
|
||||
int index = lookup->GetLocalFieldIndexFromMap(*map);
|
||||
// Negative property indices are in-object properties, indexed from the end of
|
||||
// the fixed part of the object. Non-negative property indices are in the
|
||||
// properties array.
|
||||
int inobject = index < 0;
|
||||
Representation representation = lookup->representation();
|
||||
int offset = inobject
|
||||
? index * kPointerSize + map->instance_size()
|
||||
: index * kPointerSize + FixedArray::kHeaderSize;
|
||||
return DoBuildLoadNamedField(object, inobject, representation, offset);
|
||||
}
|
||||
|
||||
|
||||
HLoadNamedField* HGraphBuilder::DoBuildLoadNamedField(
|
||||
HValue* object,
|
||||
bool inobject,
|
||||
Representation representation,
|
||||
int offset) {
|
||||
HObjectAccess access,
|
||||
Representation representation) {
|
||||
bool load_double = false;
|
||||
if (representation.IsDouble()) {
|
||||
representation = Representation::Tagged();
|
||||
load_double = FLAG_track_double_fields;
|
||||
}
|
||||
HLoadNamedField* field =
|
||||
new(zone()) HLoadNamedField(object, inobject, representation, offset);
|
||||
new(zone()) HLoadNamedField(object, access, NULL, representation);
|
||||
if (load_double) {
|
||||
AddInstruction(field);
|
||||
field->set_type(HType::HeapNumber());
|
||||
return new(zone()) HLoadNamedField(
|
||||
field, true, Representation::Double(), HeapNumber::kValueOffset);
|
||||
return new(zone()) HLoadNamedField(field,
|
||||
HObjectAccess::ForHeapNumberValue(), NULL, Representation::Double());
|
||||
}
|
||||
return field;
|
||||
}
|
||||
@ -7955,7 +7853,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
|
||||
if (name->Equals(isolate()->heap()->length_string())) {
|
||||
if (map->instance_type() == JS_ARRAY_TYPE) {
|
||||
AddCheckMapsWithTransitions(object, map);
|
||||
return HLoadNamedField::NewArrayLength(zone(), object, object);
|
||||
return new(zone()) HLoadNamedField(object,
|
||||
HObjectAccess::ForArrayLength());
|
||||
}
|
||||
}
|
||||
|
||||
@ -7963,7 +7862,9 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
|
||||
map->LookupDescriptor(NULL, *name, &lookup);
|
||||
if (lookup.IsField()) {
|
||||
AddCheckMap(object, map);
|
||||
return BuildLoadNamedField(object, map, &lookup);
|
||||
return BuildLoadNamedField(object,
|
||||
HObjectAccess::ForField(map, &lookup, name),
|
||||
ComputeLoadStoreRepresentation(map, &lookup));
|
||||
}
|
||||
|
||||
// Handle a load of a constant known function.
|
||||
@ -7982,9 +7883,11 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
|
||||
AddCheckMap(object, map);
|
||||
AddInstruction(
|
||||
new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
|
||||
HValue* holder_value = AddInstruction(
|
||||
new(zone()) HConstant(holder, Representation::Tagged()));
|
||||
return BuildLoadNamedField(holder_value, holder_map, &lookup);
|
||||
HValue* holder_value = AddInstruction(new(zone())
|
||||
HConstant(holder, Representation::Tagged()));
|
||||
return BuildLoadNamedField(holder_value,
|
||||
HObjectAccess::ForField(holder_map, &lookup, name),
|
||||
ComputeLoadStoreRepresentation(map, &lookup));
|
||||
}
|
||||
|
||||
// Handle a load of a constant function somewhere in the prototype chain.
|
||||
@ -8260,10 +8163,10 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
current_block()->Finish(typecheck);
|
||||
|
||||
set_current_block(if_jsarray);
|
||||
HInstruction* length;
|
||||
length = AddInstruction(
|
||||
HLoadNamedField::NewArrayLength(zone(), object, typecheck,
|
||||
HType::Smi()));
|
||||
HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(),
|
||||
typecheck, Representation::Smi());
|
||||
length->set_type(HType::Smi());
|
||||
|
||||
checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
|
||||
access = AddInstruction(BuildFastElementAccess(
|
||||
elements, checked_key, val, elements_kind_branch,
|
||||
@ -10903,7 +10806,6 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
|
||||
int* offset,
|
||||
AllocationSiteMode mode) {
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
|
||||
HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
|
||||
original_boilerplate_object, Representation::Tagged()));
|
||||
@ -10954,6 +10856,12 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
|
||||
Handle<Object> value =
|
||||
Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
|
||||
isolate());
|
||||
|
||||
// The access for the store depends on the type of the boilerplate.
|
||||
HObjectAccess access = boilerplate_object->IsJSArray() ?
|
||||
HObjectAccess::ForJSArrayOffset(property_offset) :
|
||||
HObjectAccess::ForJSObjectOffset(property_offset);
|
||||
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
Handle<JSObject> original_value_object = Handle<JSObject>::cast(
|
||||
@ -10961,39 +10869,39 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
|
||||
isolate()));
|
||||
HInstruction* value_instruction =
|
||||
AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
|
||||
AddInstruction(new(zone) HStoreNamedField(
|
||||
object_properties, name, value_instruction, true,
|
||||
Representation::Tagged(), property_offset));
|
||||
|
||||
AddStore(object_properties, access, value_instruction);
|
||||
|
||||
BuildEmitDeepCopy(value_object, original_value_object, target,
|
||||
offset, DONT_TRACK_ALLOCATION_SITE);
|
||||
offset, DONT_TRACK_ALLOCATION_SITE);
|
||||
} else {
|
||||
Representation representation = details.representation();
|
||||
HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
|
||||
value, Representation::Tagged()));
|
||||
|
||||
if (representation.IsDouble()) {
|
||||
// Allocate a HeapNumber box and store the value into it.
|
||||
HInstruction* double_box =
|
||||
AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
|
||||
BuildStoreMap(double_box, factory->heap_number_map());
|
||||
AddInstruction(new(zone) HStoreNamedField(
|
||||
double_box, name, value_instruction, true,
|
||||
Representation::Double(), HeapNumber::kValueOffset));
|
||||
AddStoreMapConstant(double_box,
|
||||
isolate()->factory()->heap_number_map());
|
||||
AddStore(double_box, HObjectAccess::ForHeapNumberValue(),
|
||||
value_instruction, Representation::Double());
|
||||
value_instruction = double_box;
|
||||
*offset += HeapNumber::kSize;
|
||||
}
|
||||
AddInstruction(new(zone) HStoreNamedField(
|
||||
object_properties, name, value_instruction, true,
|
||||
Representation::Tagged(), property_offset));
|
||||
|
||||
AddStore(object_properties, access, value_instruction);
|
||||
}
|
||||
}
|
||||
|
||||
int inobject_properties = boilerplate_object->map()->inobject_properties();
|
||||
HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
|
||||
factory->one_pointer_filler_map(), Representation::Tagged()));
|
||||
HInstruction* value_instruction = AddInstruction(new(zone)
|
||||
HConstant(isolate()->factory()->one_pointer_filler_map(),
|
||||
Representation::Tagged()));
|
||||
for (int i = copied_fields; i < inobject_properties; i++) {
|
||||
AddInstruction(new(zone) HStoreNamedField(
|
||||
object_properties, factory->unknown_field_string(), value_instruction,
|
||||
true, Representation::Tagged(),
|
||||
boilerplate_object->GetInObjectPropertyOffset(i)));
|
||||
HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
|
||||
AddStore(object_properties, access, value_instruction);
|
||||
}
|
||||
|
||||
// Build Allocation Site Info if desired
|
||||
@ -11067,13 +10975,12 @@ HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
|
||||
int elements_size) {
|
||||
ASSERT(boilerplate_object->properties()->length() == 0);
|
||||
Zone* zone = this->zone();
|
||||
Factory* factory = isolate()->factory();
|
||||
HValue* result = NULL;
|
||||
|
||||
HValue* object_header =
|
||||
AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
|
||||
Handle<Map> boilerplate_object_map(boilerplate_object->map());
|
||||
BuildStoreMap(object_header, boilerplate_object_map);
|
||||
AddStoreMapConstant(object_header, boilerplate_object_map);
|
||||
|
||||
HInstruction* elements;
|
||||
if (elements_size == 0) {
|
||||
@ -11086,23 +10993,15 @@ HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
|
||||
target, elements_offset));
|
||||
result = elements;
|
||||
}
|
||||
HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
|
||||
object_header,
|
||||
factory->elements_field_string(),
|
||||
elements,
|
||||
true, Representation::Tagged(), JSObject::kElementsOffset));
|
||||
elements_store->SetGVNFlag(kChangesElementsPointer);
|
||||
AddStore(object_header, HObjectAccess::ForElementsPointer(), elements);
|
||||
|
||||
Handle<Object> properties_field =
|
||||
Handle<Object>(boilerplate_object->properties(), isolate());
|
||||
ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
|
||||
HInstruction* properties = AddInstruction(new(zone) HConstant(
|
||||
properties_field, Representation::None()));
|
||||
AddInstruction(new(zone) HStoreNamedField(object_header,
|
||||
factory->empty_string(),
|
||||
properties, true,
|
||||
Representation::Tagged(),
|
||||
JSObject::kPropertiesOffset));
|
||||
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
|
||||
AddStore(object_header, access, properties);
|
||||
|
||||
if (boilerplate_object->IsJSArray()) {
|
||||
Handle<JSArray> boilerplate_array =
|
||||
@ -11111,16 +11010,13 @@ HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
|
||||
Handle<Object>(boilerplate_array->length(), isolate());
|
||||
HInstruction* length = AddInstruction(new(zone) HConstant(
|
||||
length_field, Representation::None()));
|
||||
|
||||
ASSERT(boilerplate_array->length()->IsSmi());
|
||||
Representation representation =
|
||||
IsFastElementsKind(boilerplate_array->GetElementsKind())
|
||||
? Representation::Smi() : Representation::Tagged();
|
||||
HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
|
||||
object_header,
|
||||
factory->length_field_string(),
|
||||
length,
|
||||
true, representation, JSArray::kLengthOffset));
|
||||
length_store->SetGVNFlag(kChangesArrayLengths);
|
||||
AddStore(object_header, HObjectAccess::ForArrayLength(),
|
||||
length, representation);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -11504,13 +11400,8 @@ void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
|
||||
|
||||
// Create in-object property store to kValueOffset.
|
||||
set_current_block(if_js_value);
|
||||
Handle<String> name = isolate()->factory()->undefined_string();
|
||||
AddInstruction(new(zone()) HStoreNamedField(object,
|
||||
name,
|
||||
value,
|
||||
true, // in-object store.
|
||||
Representation::Tagged(),
|
||||
JSValue::kValueOffset));
|
||||
AddStore(object,
|
||||
HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value);
|
||||
if_js_value->Goto(join);
|
||||
join->SetJoinId(call->id());
|
||||
set_current_block(join);
|
||||
|
@ -992,11 +992,6 @@ class HGraphBuilder {
|
||||
HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
|
||||
|
||||
// Building common constructs
|
||||
HLoadNamedField* DoBuildLoadNamedField(HValue* object,
|
||||
bool inobject,
|
||||
Representation representation,
|
||||
int offset);
|
||||
|
||||
HInstruction* BuildExternalArrayElementAccess(
|
||||
HValue* external_elements,
|
||||
HValue* checked_key,
|
||||
@ -1039,8 +1034,24 @@ class HGraphBuilder {
|
||||
KeyedAccessStoreMode store_mode,
|
||||
Representation checked_index_representation = Representation::None());
|
||||
|
||||
HInstruction* BuildStoreMap(HValue* object, HValue* map);
|
||||
HInstruction* BuildStoreMap(HValue* object, Handle<Map> map);
|
||||
HLoadNamedField* AddLoad(
|
||||
HValue *object,
|
||||
HObjectAccess access,
|
||||
HValue *typecheck = NULL,
|
||||
Representation representation = Representation::Tagged());
|
||||
|
||||
HLoadNamedField* BuildLoadNamedField(
|
||||
HValue* object,
|
||||
HObjectAccess access,
|
||||
Representation representation);
|
||||
|
||||
HStoreNamedField* AddStore(
|
||||
HValue *object,
|
||||
HObjectAccess access,
|
||||
HValue *val,
|
||||
Representation representation = Representation::Tagged());
|
||||
|
||||
HStoreNamedField* AddStoreMapConstant(HValue *object, Handle<Map>);
|
||||
|
||||
HLoadNamedField* AddLoadElements(HValue *object, HValue *typecheck = NULL);
|
||||
|
||||
@ -1692,9 +1703,6 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
|
||||
bool is_store,
|
||||
bool* has_side_effects);
|
||||
|
||||
HLoadNamedField* BuildLoadNamedField(HValue* object,
|
||||
Handle<Map> map,
|
||||
LookupResult* result);
|
||||
HInstruction* BuildLoadNamedGeneric(HValue* object,
|
||||
Handle<String> name,
|
||||
Property* expr);
|
||||
|
@ -416,8 +416,7 @@ LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
|
||||
|
||||
void LStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(*String::cast(*name())->ToCString());
|
||||
hydrogen()->access().PrintTo(stream);
|
||||
stream->Add(" <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
@ -373,8 +373,7 @@ void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
|
||||
|
||||
void LStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(*String::cast(*name())->ToCString());
|
||||
hydrogen()->access().PrintTo(stream);
|
||||
stream->Add(" <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
@ -341,6 +341,7 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<Name> name,
|
||||
PropertyIndex field,
|
||||
Representation representation) {
|
||||
if (receiver.is_identical_to(holder)) {
|
||||
// TODO(titzer): this should use an HObjectAccess
|
||||
KeyedLoadFieldStub stub(field.is_inobject(holder),
|
||||
field.translate(holder),
|
||||
representation);
|
||||
|
@ -391,8 +391,7 @@ LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
|
||||
|
||||
void LStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(*String::cast(*name())->ToCString());
|
||||
hydrogen()->access().PrintTo(stream);
|
||||
stream->Add(" <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user