Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index c6a2023d087a01e937fd1f9a95dae111b8d0fa47..de7ba1d0c5bf35528c3c10300b10e692c4e9238b 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7257,7 +7257,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
return constructor->has_initial_map() && |
constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
- constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize; |
+ constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
+ constructor->initial_map()->InitialPropertiesLength() == 0; |
} |
@@ -7267,6 +7268,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
ASSERT(current_block()->HasPredecessor()); |
int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
HValue* context = environment()->LookupContext(); |
+ Factory* factory = isolate()->factory(); |
if (FLAG_inline_construct && |
expr->IsMonomorphic() && |
@@ -7285,19 +7287,73 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
constructor->shared()->CompleteInobjectSlackTracking(); |
} |
- // Replace the constructor function with a newly allocated receiver. |
- HInstruction* receiver = Add<HAllocateObject>(context, constructor); |
- // Index of the receiver from the top of the expression stack. |
+ // Calculate instance size from initial map of constructor. |
+ ASSERT(constructor->has_initial_map()); |
+ Handle<Map> initial_map(constructor->initial_map()); |
+ int instance_size = initial_map->instance_size(); |
+ ASSERT(initial_map->InitialPropertiesLength() == 0); |
+ |
+ // Allocate an instance of the implicit receiver object. |
+ HValue* size_in_bytes = Add<HConstant>(instance_size); |
+ HAllocate::Flags flags = HAllocate::DefaultFlags(); |
+ if (FLAG_pretenuring_call_new && |
+ isolate()->heap()->ShouldGloballyPretenure()) { |
+ flags = static_cast<HAllocate::Flags>( |
+ flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE); |
+ } |
+ HAllocate* receiver = |
+ Add<HAllocate>(context, size_in_bytes, HType::JSObject(), flags); |
+ receiver->set_known_initial_map(initial_map); |
+ |
+ // Load the initial map from the constructor. |
+ HValue* constructor_value = Add<HConstant>(constructor); |
+ HValue* initial_map_value = |
+ AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset( |
+ JSFunction::kPrototypeOrInitialMapOffset)); |
+ |
+ // Initialize map and fields of the newly allocated object. |
+ { NoObservableSideEffectsScope no_effects(this); |
+ ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
+ AddStore(receiver, |
+ HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset), |
+ initial_map_value); |
+ HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); |
+ AddStore(receiver, |
+ HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset), |
+ empty_fixed_array); |
+ AddStore(receiver, |
+ HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset), |
+ empty_fixed_array); |
+ if (initial_map->inobject_properties() != 0) { |
+ HConstant* undefined = graph()->GetConstantUndefined(); |
+ for (int i = 0; i < initial_map->inobject_properties(); i++) { |
+ int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
+ AddStore(receiver, |
+ HObjectAccess::ForJSObjectOffset(property_offset), |
+ undefined); |
+ } |
+ } |
+ } |
+ |
+ // Replace the constructor function with a newly allocated receiver using |
+ // the index of the receiver from the top of the expression stack. |
const int receiver_index = argument_count - 1; |
ASSERT(environment()->ExpressionStackAt(receiver_index) == function); |
environment()->SetExpressionStackAt(receiver_index, receiver); |
if (TryInlineConstruct(expr, receiver)) return; |
- // TODO(mstarzinger): For now we remove the previous HAllocateObject and |
- // add HPushArgument for the arguments in case inlining failed. What we |
- // actually should do is emit HInvokeFunction on the constructor instead |
- // of using HCallNew as a fallback. |
+ // TODO(mstarzinger): For now we remove the previous HAllocate and all |
+ // corresponding instructions and instead add HPushArgument for the |
+ // arguments in case inlining failed. What we actually should do is for |
+ // inlining to try to build a subgraph without mutating the parent graph. |
+ HInstruction* instr = current_block()->last(); |
+ while (instr != initial_map_value) { |
+ HInstruction* prev_instr = instr->previous(); |
+ instr->DeleteAndReplaceWith(NULL); |
+ instr = prev_instr; |
+ } |
+ initial_map_value->DeleteAndReplaceWith(NULL); |
receiver->DeleteAndReplaceWith(NULL); |
check->DeleteAndReplaceWith(NULL); |
environment()->SetExpressionStackAt(receiver_index, function); |