Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index 9bfc11055ab9d0c7dc04426b19c1e4c6b5423380..d8662f3552ee2d0dca677b9fd4df0bdb3a5f6b1c 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -1263,8 +1263,10 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context, |
| total_size->ChangeRepresentation(Representation::Integer32()); |
| total_size->ClearFlag(HValue::kCanOverflow); |
| - HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE; |
| + HAllocate::Flags flags = HAllocate::DefaultFlags(kind); |
| if (FLAG_pretenure_literals) { |
| + // TODO(hpayer): When pretenuring can be internalized, flags can become |
| + // private to HAllocate. |
| if (IsFastDoubleElementsKind(kind)) { |
| flags = static_cast<HAllocate::Flags>( |
| flags | HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE); |
| @@ -1273,10 +1275,6 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context, |
| flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE); |
| } |
| } |
| - if (IsFastDoubleElementsKind(kind)) { |
| - flags = static_cast<HAllocate::Flags>( |
| - flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED); |
| - } |
| HValue* elements = |
| AddInstruction(new(zone) HAllocate(context, total_size, |
| @@ -1313,6 +1311,59 @@ HValue* HGraphBuilder::BuildAllocateAndInitializeElements(HValue* context, |
| } |
| +HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, |
| + HValue* array_map, |
| + AllocationSiteMode mode, |
| + HValue* allocation_site_payload, |
| + HValue* length_field) { |
| + |
| + BuildStoreMap(array, array_map); |
| + |
| + HConstant* empty_fixed_array = |
| + new(zone()) HConstant( |
| + Handle<FixedArray>(isolate()->heap()->empty_fixed_array()), |
| + Representation::Tagged()); |
| + AddInstruction(empty_fixed_array); |
| + |
| + AddInstruction(new(zone()) HStoreNamedField(array, |
| + isolate()->factory()->properties_field_symbol(), |
| + empty_fixed_array, |
| + true, |
| + JSArray::kPropertiesOffset)); |
| + |
| + AddInstruction(new(zone()) HStoreNamedField(array, |
| + isolate()->factory()->length_field_string(), |
| + length_field, |
| + true, |
| + JSArray::kLengthOffset)); |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
I think you have to take care of the GVN flags her
mvstanton
2013/04/18 13:39:26
Done.
|
| + |
| + if (mode == TRACK_ALLOCATION_SITE) { |
| + BuildCreateAllocationSiteInfo(array, |
| + JSArray::kSize, |
| + allocation_site_payload); |
| + } |
| + |
| + int elements_location = JSArray::kSize; |
| + if (mode == TRACK_ALLOCATION_SITE) { |
| + elements_location += AllocationSiteInfo::kSize; |
| + } |
| + |
| + HInnerAllocatedObject* elements = new(zone()) HInnerAllocatedObject( |
| + array, |
| + elements_location); |
| + AddInstruction(elements); |
| + |
| + AddInstruction(new(zone()) HStoreNamedField( |
| + array, |
| + isolate()->factory()->elements_field_string(), |
| + elements, |
| + true, |
| + JSArray::kElementsOffset)); |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
I think you have to take care of the GVN flags her
mvstanton
2013/04/18 13:39:26
Done.
|
| + |
| + return elements; |
| +} |
| + |
| + |
| HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
| HValue* map) { |
| Zone* zone = this->zone(); |
| @@ -1426,13 +1477,38 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context, |
| : AddInstruction(new(zone) HConstant(nan_double, |
| Representation::Double())); |
| - LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); |
| + // Special loop unfolding case |
| + static const int kLoopUnfoldLimit = 4; |
| + bool unfold_loop = false; |
| + int initial_capacity = JSArray::kPreallocatedArrayElements; |
| + if (from->IsConstant() && to->IsConstant() && |
| + initial_capacity <= kLoopUnfoldLimit) { |
| + HConstant* constant_from = HConstant::cast(from); |
| + HConstant* constant_to = HConstant::cast(to); |
| - HValue* key = builder.BeginBody(from, to, Token::LT); |
| + if (constant_from->HasInteger32Value() && |
| + constant_from->Integer32Value() == 0 && |
| + constant_to->HasInteger32Value() && |
| + constant_to->Integer32Value() == initial_capacity) { |
| + unfold_loop = true; |
| + } |
| + } |
| - AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); |
| + if (unfold_loop) { |
| + for (int i = 0; i < initial_capacity; i++) { |
| + HInstruction* key = AddInstruction(new(zone) |
| + HConstant(i, Representation::Integer32())); |
| + AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); |
| + } |
| + } else { |
| + LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); |
| - builder.EndBody(); |
| + HValue* key = builder.BeginBody(from, to, Token::LT); |
| + |
| + AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); |
| + |
| + builder.EndBody(); |
| + } |
| } |
| @@ -1499,12 +1575,7 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, |
| : FixedArray::SizeFor(length); |
| } |
| - HAllocate::Flags allocate_flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE; |
| - if (IsFastDoubleElementsKind(kind)) { |
| - allocate_flags = static_cast<HAllocate::Flags>( |
| - allocate_flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED); |
| - } |
| - |
| + HAllocate::Flags allocate_flags = HAllocate::DefaultFlags(kind); |
| // Allocate both the JS array and the elements array in one big |
| // allocation. This avoids multiple limit checks. |
| HValue* size_in_bytes = |
| @@ -1533,15 +1604,7 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, |
| // Create an allocation site info if requested. |
| if (mode == TRACK_ALLOCATION_SITE) { |
| - HValue* alloc_site = |
| - AddInstruction(new(zone) HInnerAllocatedObject(object, JSArray::kSize)); |
| - Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map()); |
| - BuildStoreMap(alloc_site, alloc_site_map); |
| - int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset; |
| - AddInstruction(new(zone) HStoreNamedField(alloc_site, |
| - factory->empty_string(), |
| - boilerplate, |
| - true, alloc_payload_offset)); |
| + BuildCreateAllocationSiteInfo(object, JSArray::kSize, boilerplate); |
| } |
| if (length > 0) { |
| @@ -1590,6 +1653,159 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, |
| } |
| +HValue* HGraphBuilder::BuildCreateAllocationSiteInfo(HValue* previous_object, |
| + int previous_object_size, |
| + HValue* payload) { |
| + HInnerAllocatedObject* alloc_site = new(zone()) |
| + 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, |
| + AllocationSiteInfo::kPayloadOffset)); |
| + return alloc_site; |
| +} |
| + |
| + |
| +HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, |
| + ElementsKind kind, |
| + HValue* allocation_site_payload, |
| + AllocationSiteMode mode) : |
| + builder_(builder), |
| + kind_(kind), |
| + allocation_site_payload_(allocation_site_payload) { |
| + // Determine mode |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
you can remove the comment, the following code sho
mvstanton
2013/04/18 13:39:26
Done.
|
| + if (mode == DONT_TRACK_ALLOCATION_SITE) { |
| + mode_ = mode; |
| + } else { |
| + mode_ = AllocationSiteInfo::GetMode(kind); |
| + } |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) { |
| + // Get the global context, the native context, the map array |
| + HInstruction* global_object = AddInstruction(new(zone()) |
| + HGlobalObject(context)); |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
Why do you need the global_object?
mvstanton
2013/04/18 13:39:26
You mean instead of saying isolate()->native_conte
Hannes Payer (out of office)
2013/04/23 11:42:50
Never mind, keep it...
|
| + HInstruction* native_context = AddInstruction(new(zone()) |
| + HLoadNamedField(global_object, true, GlobalObject::kNativeContextOffset)); |
| + size_t offset = Context::kHeaderSize + |
| + kPointerSize * Context::JS_ARRAY_MAPS_INDEX; |
| + HInstruction* map_array = AddInstruction(new(zone()) |
| + HLoadNamedField(native_context, true, offset)); |
| + offset = kind_ * kPointerSize + FixedArrayBase::kHeaderSize; |
| + return AddInstruction(new(zone()) HLoadNamedField(map_array, true, offset)); |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( |
| + HValue* length_node) { |
| + HValue* context = builder()->environment()->LookupContext(); |
| + ASSERT(length_node != NULL); |
| + |
| + int base_size = JSArray::kSize; |
| + if (mode_ == TRACK_ALLOCATION_SITE) { |
| + base_size += AllocationSiteInfo::kSize; |
| + } |
| + |
| + if (IsFastDoubleElementsKind(kind_)) { |
| + base_size += FixedDoubleArray::kHeaderSize; |
| + } else { |
| + base_size += FixedArray::kHeaderSize; |
| + } |
| + |
| + HInstruction* elements_size_value = new(zone()) |
| + HConstant(elements_size(), Representation::Integer32()); |
| + AddInstruction(elements_size_value); |
| + HInstruction* mul = HMul::New(zone(), context, length_node, |
| + elements_size_value); |
| + mul->ChangeRepresentation(Representation::Integer32()); |
| + mul->ClearFlag(HValue::kCanOverflow); |
| + AddInstruction(mul); |
| + |
| + HInstruction* base = new(zone()) HConstant(base_size, |
| + Representation::Integer32()); |
| + AddInstruction(base); |
| + HInstruction* total_size = HAdd::New(zone(), context, base, mul); |
| + total_size->ChangeRepresentation(Representation::Integer32()); |
| + total_size->ClearFlag(HValue::kCanOverflow); |
| + AddInstruction(total_size); |
| + return total_size; |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { |
| + int base_size = JSArray::kSize; |
| + if (mode_ == TRACK_ALLOCATION_SITE) { |
| + base_size += AllocationSiteInfo::kSize; |
| + } |
| + |
| + base_size += IsFastDoubleElementsKind(kind_) |
| + ? FixedDoubleArray::SizeFor(initial_capacity()) |
| + : FixedArray::SizeFor(initial_capacity()); |
| + |
| + HConstant* array_size = |
| + new(zone()) HConstant(base_size, Representation::Integer32()); |
| + AddInstruction(array_size); |
| + return array_size; |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { |
| + HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); |
| + HConstant* capacity = |
| + new(zone()) HConstant(initial_capacity(), Representation::Integer32()); |
| + AddInstruction(capacity); |
| + return AllocateArray(size_in_bytes, |
| + capacity, |
| + builder()->graph()->GetConstant0(), |
| + true); |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, |
| + HValue* length_field, |
| + bool fill_with_hole) { |
| + HValue* size_in_bytes = EstablishAllocationSize(capacity); |
| + return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
| + HValue* capacity, |
| + HValue* length_field, |
| + bool fill_with_hole) { |
| + HValue* context = builder()->environment()->LookupContext(); |
| + |
| + // Allocate (dealing with failure appropriately) |
| + HAllocate::Flags flags = HAllocate::DefaultFlags(kind_); |
| + HAllocate* new_object = new(zone()) HAllocate(context, size_in_bytes, |
| + HType::JSArray(), flags); |
| + AddInstruction(new_object); |
| + |
| + // Fill in the fields: map, properties, length |
| + HValue* map = EmitMapCode(context); |
| + elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| + map, |
| + mode_, |
| + allocation_site_payload_, |
| + length_field); |
| + |
| + // Initialize the elements |
| + builder()->BuildInitializeElements(elements_location_, kind_, capacity); |
| + |
| + if (fill_with_hole) { |
| + builder()->BuildFillElementsWithHole(context, elements_location_, kind_, |
| + graph()->GetConstant0(), capacity); |
| + } |
| + |
| + return new_object; |
| +} |
| + |
| + |
| HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
| TypeFeedbackOracle* oracle) |
| : HGraphBuilder(info), |
| @@ -9059,19 +9275,32 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| } else { |
| // The constructor function is both an operand to the instruction and an |
| // argument to the construct call. |
| + bool use_call_new_array = FLAG_optimize_constructed_arrays && |
| + !(expr->target().is_null()) && |
| + *(expr->target()) == isolate()->global_context()->array_function(); |
| + |
| CHECK_ALIVE(VisitArgument(expr->expression())); |
| HValue* constructor = HPushArgument::cast(Top())->argument(); |
| CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| HCallNew* call; |
| - if (FLAG_optimize_constructed_arrays && |
| - !(expr->target().is_null()) && |
| - *(expr->target()) == isolate()->global_context()->array_function()) { |
| + if (use_call_new_array) { |
| + AddInstruction(new(zone()) HCheckFunction(constructor, |
| + Handle<JSFunction>(isolate()->global_context()->array_function()))); |
| Handle<Object> feedback = oracle()->GetInfo(expr->CallNewFeedbackId()); |
| ASSERT(feedback->IsSmi()); |
| + // TODO(mvstanton): This is a bug because it makes a new JS property cell. |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
As discussed offline, this is not a bug but one co
mvstanton
2013/04/18 13:39:26
Done.
|
| + // INstead we need to use the same property cell as we used in the full |
| + // code gen case. The right way to do that is to begin passing the cell to |
|
Hannes Payer (out of office)
2013/04/18 11:14:39
Instead
|
| + // the type feedback oracle instead of just the value in the cell. Almost |
| + // everyone will then just be interested in the value, but in my special |
| + // case I am interested in the cell itself (as well as the value). |
| Handle<JSGlobalPropertyCell> cell = |
| isolate()->factory()->NewJSGlobalPropertyCell(feedback); |
| - AddInstruction(new(zone()) HCheckFunction(constructor, |
| - Handle<JSFunction>(isolate()->global_context()->array_function()))); |
| + |
| + // TODO(mvstanton): Here we should probably insert code to check if the |
| + // type cell elements kind is different from when we compiled, and deopt |
| + // in that case. Right now we don't because of environment/simulate |
| + // issues. |
| call = new(zone()) HCallNewArray(context, constructor, argument_count, |
| cell); |
| } else { |
| @@ -10200,15 +10429,7 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy( |
| // 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); |
| - int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset; |
| - AddInstruction(new(zone) HStoreNamedField(alloc_site, |
| - factory->payload_string(), |
| - original_boilerplate, |
| - true, alloc_payload_offset)); |
| + BuildCreateAllocationSiteInfo(target, JSArray::kSize, original_boilerplate); |
| } |
| if (object_elements != NULL) { |