};
+// 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);
} 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); }
}
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();
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_;
};
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)
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; }
}
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_;
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();
}
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));
}
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);
}
HValue* allocation_site_payload,
HValue* length_field) {
- BuildStoreMap(array, array_map);
+ AddStore(array, HObjectAccess::ForMap(), array_map);
HConstant* empty_fixed_array =
new(zone()) HConstant(
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,
}
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);
}
ElementsKind kind,
HValue* length,
HValue* new_capacity) {
- Zone* zone = this->zone();
HValue* context = environment()->LookupContext();
BuildNewSpaceArrayCheck(new_capacity, kind);
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;
}
ElementsKind kind,
int length) {
Zone* zone = this->zone();
- Factory* factory = isolate()->factory();
NoObservableSideEffectsScope no_effects(this);
// 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));
}
}
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.
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));
}
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));
}
}
+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),
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();
}
-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()) {
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);
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;
// 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;
-
- int index = ComputeLoadStoreFieldIndex(map, &lookup);
- Representation new_representation =
- ComputeLoadStoreRepresentation(map, &lookup);
- bool is_in_object = index < 0;
- 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;
- }
-
- 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);
+ 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;
+
+ HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
+ Representation new_representation =
+ ComputeLoadStoreRepresentation(map, &lookup);
+
+ 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());
}
-HLoadNamedField* HOptimizedGraphBuilder::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(
+HLoadNamedField* HGraphBuilder::BuildLoadNamedField(
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;
}
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());
}
}
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.
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.
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,
int* offset,
AllocationSiteMode mode) {
Zone* zone = this->zone();
- Factory* factory = isolate()->factory();
HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
original_boilerplate_object, Representation::Tagged()));
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(
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
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) {
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 =
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;
// 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);