Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 0a6d1dfdbc84b03c5e75dff019e76ebbd3ca2492..b6649b98efdde3c18807f60f621b53f89612eb5d 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -6176,33 +6176,38 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
// Check whether to use fast or slow deep-copying for boilerplate. |
int total_size = 0; |
- int max_properties = HFastLiteral::kMaxLiteralProperties; |
- Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()), |
- isolate()); |
- if (boilerplate->IsJSObject() && |
- IsFastLiteral(Handle<JSObject>::cast(boilerplate), |
- HFastLiteral::kMaxLiteralDepth, |
+ int max_properties = kMaxFastLiteralProperties; |
+ Handle<Object> original_boilerplate(closure->literals()->get( |
+ expr->literal_index()), isolate()); |
+ if (original_boilerplate->IsJSObject() && |
+ IsFastLiteral(Handle<JSObject>::cast(original_boilerplate), |
+ kMaxFastLiteralDepth, |
&max_properties, |
&total_size)) { |
- Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate); |
- literal = new(zone()) HFastLiteral(context, |
- boilerplate_object, |
- total_size, |
- expr->literal_index(), |
- expr->depth(), |
- DONT_TRACK_ALLOCATION_SITE); |
+ Handle<JSObject> original_boilerplate_object = |
+ Handle<JSObject>::cast(original_boilerplate); |
+ Handle<JSObject> boilerplate_object = |
+ DeepCopy(original_boilerplate_object); |
+ |
+ literal = BuildFastLiteral(context, |
+ boilerplate_object, |
+ original_boilerplate_object, |
+ total_size, |
+ DONT_TRACK_ALLOCATION_SITE, |
+ environment()->previous_ast_id()); |
} else { |
- literal = new(zone()) HObjectLiteral(context, |
- expr->constant_properties(), |
- expr->fast_elements(), |
- expr->literal_index(), |
- expr->depth(), |
- expr->has_function()); |
+ literal = AddInstruction( |
+ new(zone()) HObjectLiteral(context, |
danno
2013/04/09 08:52:42
nit: strange indenting?
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ expr->constant_properties(), |
+ expr->fast_elements(), |
+ expr->literal_index(), |
+ expr->depth(), |
+ expr->has_function())); |
} |
// The object is expected in the bailout environment during computation |
// of the property values and is the value of the entire expression. |
- PushAndAdd(literal); |
+ Push(literal); |
expr->CalculateEmitStore(zone()); |
@@ -6299,9 +6304,10 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
} |
} |
- Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate); |
+ Handle<JSObject> original_boilerplate_object = |
+ Handle<JSObject>::cast(raw_boilerplate); |
ElementsKind boilerplate_elements_kind = |
- Handle<JSObject>::cast(boilerplate)->GetElementsKind(); |
+ Handle<JSObject>::cast(original_boilerplate_object)->GetElementsKind(); |
// TODO(mvstanton): This heuristic is only a temporary solution. In the |
// end, we want to quit creating allocation site info after a certain number |
@@ -6311,32 +6317,35 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
// Check whether to use fast or slow deep-copying for boilerplate. |
int total_size = 0; |
- int max_properties = HFastLiteral::kMaxLiteralProperties; |
- if (IsFastLiteral(boilerplate, |
- HFastLiteral::kMaxLiteralDepth, |
+ int max_properties = kMaxFastLiteralProperties; |
+ if (IsFastLiteral(original_boilerplate_object, |
+ kMaxFastLiteralDepth, |
&max_properties, |
&total_size)) { |
if (mode == TRACK_ALLOCATION_SITE) { |
total_size += AllocationSiteInfo::kSize; |
} |
- literal = new(zone()) HFastLiteral(context, |
- boilerplate, |
- total_size, |
- expr->literal_index(), |
- expr->depth(), |
- mode); |
+ |
+ Handle<JSObject> boilerplate_object = DeepCopy(original_boilerplate_object); |
+ literal = BuildFastLiteral(context, |
+ boilerplate_object, |
+ original_boilerplate_object, |
+ total_size, |
+ mode, |
+ environment()->previous_ast_id()); |
} else { |
- literal = new(zone()) HArrayLiteral(context, |
- boilerplate, |
- length, |
- expr->literal_index(), |
- expr->depth(), |
- mode); |
+ literal = AddInstruction( |
+ new(zone()) HArrayLiteral(context, |
+ original_boilerplate_object, |
+ length, |
+ expr->literal_index(), |
+ expr->depth(), |
+ mode)); |
} |
// The array is expected in the bailout environment during computation |
// of the property values and is the value of the entire expression. |
- PushAndAdd(literal); |
+ Push(literal); |
HLoadElements* elements = NULL; |
@@ -10076,6 +10085,238 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { |
} |
+HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( |
+ HValue* context, |
+ Handle<JSObject> boilerplate_object, |
+ Handle<JSObject> original_boilerplate_object, |
+ int size, |
+ AllocationSiteMode mode, |
+ BailoutId id) { |
+ Zone* zone = this->zone(); |
+ |
+ HValue* size_in_bytes = |
+ AddInstruction(new(zone) HConstant(size, Representation::Integer32())); |
+ HInstruction* result = |
+ AddInstruction(new(zone) HAllocate(context, |
+ size_in_bytes, |
+ HType::JSObject(), |
+ HAllocate::CAN_ALLOCATE_IN_NEW_SPACE)); |
+ int offset = 0; |
+ BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, result, |
+ &offset, mode, id); |
+ ASSERT_EQ(size, offset); |
+ return result; |
+} |
+ |
+ |
+void HOptimizedGraphBuilder::BuildEmitDeepCopy( |
+ Handle<JSObject> boilerplate_object, |
+ Handle<JSObject> original_boilerplate_object, |
+ HInstruction* target, |
+ int* offset, |
+ AllocationSiteMode mode, |
+ BailoutId id) { |
+ Zone* zone = this->zone(); |
+ Factory* factory = isolate()->factory(); |
+ |
+ HInstruction* boilerplate = AddInstruction(new(zone) HConstant( |
+ boilerplate_object, Representation::Tagged())); |
+ HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant( |
+ original_boilerplate_object, Representation::Tagged())); |
+ |
+ bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE && |
+ boilerplate_object->map()->CanTrackAllocationSite(); |
+ |
+ // Only elements backing stores for non-COW arrays need to be copied. |
+ Handle<FixedArrayBase> elements(boilerplate_object->elements()); |
+ Handle<FixedArrayBase> original_elements( |
+ original_boilerplate_object->elements()); |
+ ElementsKind kind = boilerplate_object->map()->elements_kind(); |
+ bool has_elements = elements->length() > 0 && |
+ elements->map() != isolate()->heap()->fixed_cow_array_map(); |
+ |
+ // Increase the offset so that subsequent objects end up right after |
+ // this object and its backing store. |
+ int object_offset = *offset; |
+ int object_size = boilerplate_object->map()->instance_size(); |
+ int elements_size = has_elements ? elements->Size() : 0; |
+ int elements_offset = *offset + object_size; |
+ int inobject_properties = boilerplate_object->map()->inobject_properties(); |
+ if (create_allocation_site_info) { |
+ elements_offset += AllocationSiteInfo::kSize; |
+ *offset += AllocationSiteInfo::kSize; |
+ } |
+ |
+ *offset += object_size + elements_size; |
+ |
+ BuildCopyObjectHeader(boilerplate_object, target, object_offset, |
+ elements_offset, has_elements, id); |
+ |
+ // Copy in-object properties. |
+ HValue* object_properties = |
+ AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset)); |
+ for (int i = 0; i < inobject_properties; i++) { |
+ Handle<Object> value = |
+ Handle<Object>(boilerplate_object->InObjectPropertyAt(i), |
+ isolate()); |
+ if (value->IsJSObject()) { |
+ Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
+ Handle<JSObject> original_value_object = Handle<JSObject>::cast( |
+ Handle<Object>(original_boilerplate_object->InObjectPropertyAt(i), |
+ isolate())); |
+ HInstruction* value_instruction = |
+ AddInstruction(new(zone) HInnerAllocatedObject(target, *offset)); |
+ AddInstruction(new(zone) HStoreNamedField( |
+ object_properties, factory->empty_string(), value_instruction, true, |
+ boilerplate_object->GetInObjectPropertyOffset(i))); |
+ AddSimulate(id); |
+ BuildEmitDeepCopy(value_object, original_value_object, target, |
+ offset, DONT_TRACK_ALLOCATION_SITE, id); |
+ } else { |
+ HInstruction* value_instruction = AddInstruction(new(zone) HConstant( |
+ value, Representation::Tagged())); |
+ AddInstruction(new(zone) HStoreNamedField( |
+ object_properties, factory->empty_string(), value_instruction, true, |
+ boilerplate_object->GetInObjectPropertyOffset(i))); |
+ AddSimulate(id); |
+ } |
+ } |
+ |
+ // Build Allocation Site Info if desired |
+ if (create_allocation_site_info) { |
+ HValue* alloc_site = |
+ AddInstruction(new(zone) HInnerAllocatedObject(target, JSArray::kSize)); |
+ Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map()); |
+ BuildStoreMap(alloc_site, alloc_site_map, id); |
+ int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset; |
+ AddInstruction(new(zone) HStoreNamedField(alloc_site, |
+ factory->payload_string(), |
+ original_boilerplate, |
+ true, alloc_payload_offset)); |
+ AddSimulate(id); |
+ } |
+ |
+ if (has_elements) { |
+ HInstruction* boilerplate_elements = |
danno
2013/04/09 08:52:42
From here....
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ AddInstruction(new(zone) HLoadElements(boilerplate, NULL)); |
+ HValue* object_elements = |
+ AddInstruction(new(zone) HInnerAllocatedObject( |
+ target, elements_offset)); |
+ AddInstruction(new(zone) HStoreNamedField(object_elements, |
+ factory->elements_field_string(), |
+ boilerplate_elements, |
+ true, JSObject::kElementsOffset)); |
danno
2013/04/09 08:52:42
... til here is not needed.
This is a FixedArray,
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ AddSimulate(id); |
+ |
danno
2013/04/09 08:52:42
ASSERT(kFixedArrayHeaderSize = 2 * kPointer);
Hannes Payer (out of office)
2013/04/09 14:20:13
What do you want to check but that assert?
|
+ HInstruction* object_elements_length = |
+ AddInstruction(new(zone) HFixedArrayBaseLength(boilerplate_elements)); |
danno
2013/04/09 08:52:42
You can replace this with a constant load, too.
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ BuildInitializeElements(object_elements, kind, object_elements_length); |
+ |
+ // Copy elements backing store content. |
+ int elements_length = elements->length(); |
+ if (elements->IsFixedDoubleArray()) { |
+ for (int i = 0; i < elements_length; i++) { |
+ HValue* key_constant = |
+ AddInstruction(new(zone) HConstant(i, Representation::Integer32())); |
+ HInstruction* value_instruction = |
+ AddInstruction(new(zone) HLoadKeyed( |
+ boilerplate_elements, key_constant, NULL, kind)); |
+ AddInstruction(new(zone) HStoreKeyed( |
+ object_elements, key_constant, value_instruction, kind)); |
+ AddSimulate(id); |
+ } |
+ } else if (elements->IsFixedArray()) { |
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); |
+ Handle<FixedArray> original_fast_elements = |
+ Handle<FixedArray>::cast(original_elements); |
+ for (int i = 0; i < elements_length; i++) { |
+ Handle<Object> value(fast_elements->get(i), isolate()); |
+ HValue* key_constant = |
+ AddInstruction(new(zone) HConstant(i, Representation::Integer32())); |
+ if (value->IsJSObject()) { |
+ Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
+ Handle<JSObject> original_value_object = Handle<JSObject>::cast( |
+ Handle<Object>(original_fast_elements->get(i), isolate())); |
+ HInstruction* value_instruction = |
+ AddInstruction(new(zone) HInnerAllocatedObject(target, *offset)); |
+ AddInstruction(new(zone) HStoreKeyed( |
+ object_elements, key_constant, value_instruction, kind)); |
+ AddSimulate(id); |
+ BuildEmitDeepCopy(value_object, original_value_object, target, |
+ offset, DONT_TRACK_ALLOCATION_SITE, id); |
+ } else { |
+ HInstruction* value_instruction = |
+ AddInstruction(new(zone) HLoadKeyed( |
+ boilerplate_elements, key_constant, NULL, kind)); |
+ AddInstruction(new(zone) HStoreKeyed( |
+ object_elements, key_constant, value_instruction, kind)); |
+ AddSimulate(id); |
+ } |
+ } |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ } |
+} |
+ |
+ |
+void HOptimizedGraphBuilder::BuildCopyObjectHeader( |
+ Handle<JSObject> boilerplate_object, |
+ HInstruction* target, |
+ int object_offset, |
+ int elements_offset, |
+ bool has_elements, |
+ BailoutId id) { |
+ ASSERT(boilerplate_object->properties()->length() == 0); |
+ Zone* zone = this->zone(); |
+ Factory* factory = isolate()->factory(); |
+ |
+ HValue* object_header = |
+ AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset)); |
+ Handle<Map> boilerplate_object_map(boilerplate_object->map()); |
+ BuildStoreMap(object_header, boilerplate_object_map, id); |
+ |
+ HInstruction* value_instruction; |
danno
2013/04/09 08:52:42
Maybe different names? elements?
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ Handle<Object> header_field ; |
+ if (!has_elements) { |
+ header_field = Handle<Object>(boilerplate_object->elements(), isolate()); |
+ value_instruction = AddInstruction(new(zone) HConstant( |
+ header_field, Representation::None())); |
danno
2013/04/09 08:52:42
Tagged
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ } else { |
+ value_instruction = AddInstruction(new(zone) HInnerAllocatedObject( |
+ target, elements_offset)); |
+ } |
+ AddInstruction(new(zone) HStoreNamedField(object_header, |
+ factory->empty_string(), |
danno
2013/04/09 08:52:42
nit: indent
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ value_instruction, |
+ true, JSObject::kElementsOffset)); |
+ AddSimulate(id); |
danno
2013/04/09 08:52:42
Make sure to set the kChangesElementsPointer GVN f
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ |
+ header_field = Handle<Object>(boilerplate_object->properties(), isolate()); |
+ value_instruction = AddInstruction(new(zone) HConstant( |
danno
2013/04/09 08:52:42
properties
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ header_field, Representation::None())); |
+ AddInstruction(new(zone) HStoreNamedField(object_header, |
+ factory->empty_string(), |
+ value_instruction, |
+ true, JSObject::kPropertiesOffset)); |
danno
2013/04/09 08:52:42
As discussed, perhaps you only want to do this in
Hannes Payer (out of office)
2013/04/09 14:20:13
This belongs to elements. Done.
|
+ AddSimulate(id); |
+ |
+ if (boilerplate_object->IsJSArray()) { |
+ Handle<JSArray> boilerplate_array = |
+ Handle<JSArray>::cast(boilerplate_object); |
+ |
+ header_field = Handle<Object>(boilerplate_array->length(), isolate()); |
+ value_instruction = AddInstruction(new(zone) HConstant( |
+ header_field, Representation::None())); |
+ AddInstruction(new(zone) HStoreNamedField(object_header, |
+ factory->empty_string(), |
danno
2013/04/09 08:52:42
length_field_string
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ value_instruction, |
+ true, JSArray::kLengthOffset)); |
danno
2013/04/09 08:52:42
Make sure to set the kChangesArrayLengths GVN flag
Hannes Payer (out of office)
2013/04/09 14:20:13
Done.
|
+ AddSimulate(id); |
+ } |
+} |
+ |
+ |
void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
ASSERT(!HasStackOverflow()); |
ASSERT(current_block() != NULL); |