Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Unified Diff: src/hydrogen.cc

Issue 12385014: Hydrogen stubs for array constructors (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: We still generated the arrays with feature flag off. Fixed. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 20e1d0d3412d08f60c77fde1d03657f766b408db..40320b7d6bbd686693d47e38befccbf7ab0daa5c 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1341,8 +1341,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);
@@ -1351,10 +1353,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,
@@ -1390,6 +1388,63 @@ 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));
+
+ HInstruction* length_store = AddInstruction(
+ new(zone()) HStoreNamedField(array,
+ isolate()->factory()->length_field_string(),
+ length_field,
+ true,
+ JSArray::kLengthOffset));
+ length_store->SetGVNFlag(kChangesArrayLengths);
+
+ 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);
+
+ HInstruction* elements_store = AddInstruction(
+ new(zone()) HStoreNamedField(
+ array,
+ isolate()->factory()->elements_field_string(),
+ elements,
+ true,
+ JSArray::kElementsOffset));
+ elements_store->SetGVNFlag(kChangesElementsPointer);
+
+ return elements;
+}
+
+
HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
HValue* map) {
Zone* zone = this->zone();
@@ -1503,13 +1558,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);
+
+ if (constant_from->HasInteger32Value() &&
+ constant_from->Integer32Value() == 0 &&
+ constant_to->HasInteger32Value() &&
+ constant_to->Integer32Value() == initial_capacity) {
+ unfold_loop = true;
+ }
+ }
+
+ 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);
- HValue* key = builder.BeginBody(from, to, Token::LT);
+ HValue* key = builder.BeginBody(from, to, Token::LT);
- AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind));
+ AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind));
- builder.EndBody();
+ builder.EndBody();
+ }
}
@@ -1576,12 +1656,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 =
@@ -1610,15 +1685,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) {
@@ -1667,6 +1734,158 @@ 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) {
+ 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));
+ 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),
@@ -9215,19 +9434,31 @@ 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): It would be better to use the already created global
+ // property cell that is shared by full code gen. That way, any transition
+ // information that happened after crankshaft won't be lost. The right
+ // way to do that is to begin passing the cell to the type feedback oracle
+ // instead of just the value in the cell. Do this in a follow-up checkin.
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. Do this in a follow-up checin.
call = new(zone()) HCallNewArray(context, constructor, argument_count,
cell);
} else {
@@ -10340,15 +10571,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) {
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698