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