OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 8740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8751 | 8751 |
8752 call->set_position(expr->position()); | 8752 call->set_position(expr->position()); |
8753 return ast_context()->ReturnInstruction(call, expr->id()); | 8753 return ast_context()->ReturnInstruction(call, expr->id()); |
8754 } | 8754 } |
8755 | 8755 |
8756 | 8756 |
8757 // Checks whether allocation using the given constructor can be inlined. | 8757 // Checks whether allocation using the given constructor can be inlined. |
8758 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 8758 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
8759 return constructor->has_initial_map() && | 8759 return constructor->has_initial_map() && |
8760 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 8760 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
8761 constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize; | 8761 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 8762 constructor->initial_map()->InitialPropertiesLength() == 0; |
8762 } | 8763 } |
8763 | 8764 |
8764 | 8765 |
8765 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 8766 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
8766 ASSERT(!HasStackOverflow()); | 8767 ASSERT(!HasStackOverflow()); |
8767 ASSERT(current_block() != NULL); | 8768 ASSERT(current_block() != NULL); |
8768 ASSERT(current_block()->HasPredecessor()); | 8769 ASSERT(current_block()->HasPredecessor()); |
8769 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 8770 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
8770 HValue* context = environment()->LookupContext(); | 8771 HValue* context = environment()->LookupContext(); |
| 8772 Factory* factory = isolate()->factory(); |
8771 | 8773 |
8772 if (FLAG_inline_construct && | 8774 if (FLAG_inline_construct && |
8773 expr->IsMonomorphic() && | 8775 expr->IsMonomorphic() && |
8774 IsAllocationInlineable(expr->target())) { | 8776 IsAllocationInlineable(expr->target())) { |
8775 // The constructor function is on the stack in the unoptimized code | 8777 // The constructor function is on the stack in the unoptimized code |
8776 // during evaluation of the arguments. | 8778 // during evaluation of the arguments. |
8777 CHECK_ALIVE(VisitForValue(expr->expression())); | 8779 CHECK_ALIVE(VisitForValue(expr->expression())); |
8778 HValue* function = Top(); | 8780 HValue* function = Top(); |
8779 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8781 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8780 Handle<JSFunction> constructor = expr->target(); | 8782 Handle<JSFunction> constructor = expr->target(); |
8781 HValue* check = AddInstruction( | 8783 HValue* check = AddInstruction( |
8782 new(zone()) HCheckFunction(function, constructor)); | 8784 new(zone()) HCheckFunction(function, constructor)); |
8783 | 8785 |
8784 // Force completion of inobject slack tracking before generating | 8786 // Force completion of inobject slack tracking before generating |
8785 // allocation code to finalize instance size. | 8787 // allocation code to finalize instance size. |
8786 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 8788 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
8787 constructor->shared()->CompleteInobjectSlackTracking(); | 8789 constructor->shared()->CompleteInobjectSlackTracking(); |
8788 } | 8790 } |
8789 | 8791 |
8790 // Replace the constructor function with a newly allocated receiver. | 8792 // Calculate instance size from initial map of constructor. |
8791 HInstruction* receiver = new(zone()) HAllocateObject(context, constructor); | 8793 ASSERT(constructor->has_initial_map()); |
8792 // Index of the receiver from the top of the expression stack. | 8794 Handle<Map> initial_map(constructor->initial_map()); |
| 8795 int instance_size = initial_map->instance_size(); |
| 8796 ASSERT(initial_map->InitialPropertiesLength() == 0); |
| 8797 |
| 8798 // Allocate an instance of the implicit receiver object. |
| 8799 HValue* size_in_bytes = |
| 8800 AddInstruction(new(zone()) HConstant(instance_size, |
| 8801 Representation::Integer32())); |
| 8802 HInstruction* receiver = |
| 8803 AddInstruction(new(zone()) HAllocate(context, |
| 8804 size_in_bytes, |
| 8805 HType::JSObject(), |
| 8806 HAllocate::DefaultFlags())); |
| 8807 HAllocate::cast(receiver)->set_known_initial_map(initial_map); |
| 8808 |
| 8809 // Load the initial map from the constructor. |
| 8810 HValue* constructor_value = |
| 8811 AddInstruction(new(zone()) HConstant(constructor, |
| 8812 Representation::Tagged())); |
| 8813 HValue* initial_map_value = |
| 8814 AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset( |
| 8815 JSFunction::kPrototypeOrInitialMapOffset)); |
| 8816 |
| 8817 // Initialize map and fields of the newly allocated object. |
| 8818 { NoObservableSideEffectsScope no_effects(this); |
| 8819 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 8820 AddStore(receiver, |
| 8821 HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset), |
| 8822 initial_map_value); |
| 8823 HValue* empty_fixed_array = |
| 8824 AddInstruction(new(zone()) HConstant(factory->empty_fixed_array(), |
| 8825 Representation::Tagged())); |
| 8826 AddStore(receiver, |
| 8827 HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset), |
| 8828 empty_fixed_array); |
| 8829 AddStore(receiver, |
| 8830 HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset), |
| 8831 empty_fixed_array); |
| 8832 if (initial_map->inobject_properties() != 0) { |
| 8833 HConstant* undefined = graph()->GetConstantUndefined(); |
| 8834 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 8835 int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
| 8836 AddStore(receiver, |
| 8837 HObjectAccess::ForJSObjectOffset(property_offset), |
| 8838 undefined); |
| 8839 } |
| 8840 } |
| 8841 } |
| 8842 |
| 8843 // Replace the constructor function with a newly allocated receiver using |
| 8844 // the index of the receiver from the top of the expression stack. |
8793 const int receiver_index = argument_count - 1; | 8845 const int receiver_index = argument_count - 1; |
8794 AddInstruction(receiver); | |
8795 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); | 8846 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); |
8796 environment()->SetExpressionStackAt(receiver_index, receiver); | 8847 environment()->SetExpressionStackAt(receiver_index, receiver); |
8797 | 8848 |
8798 if (TryInlineConstruct(expr, receiver)) return; | 8849 if (TryInlineConstruct(expr, receiver)) return; |
8799 | 8850 |
8800 // TODO(mstarzinger): For now we remove the previous HAllocateObject and | 8851 // TODO(mstarzinger): For now we remove the previous HAllocate and all |
8801 // add HPushArgument for the arguments in case inlining failed. What we | 8852 // corresponding instructions and instead add HPushArgument for the |
8802 // actually should do is emit HInvokeFunction on the constructor instead | 8853 // arguments in case inlining failed. What we actually should do is for |
8803 // of using HCallNew as a fallback. | 8854 // inlining to try to build a subgraph without mutating the parent graph. |
| 8855 HInstruction* instr = current_block()->last(); |
| 8856 while (instr != initial_map_value) { |
| 8857 HInstruction* prev_instr = instr->previous(); |
| 8858 instr->DeleteAndReplaceWith(NULL); |
| 8859 instr = prev_instr; |
| 8860 } |
| 8861 initial_map_value->DeleteAndReplaceWith(NULL); |
8804 receiver->DeleteAndReplaceWith(NULL); | 8862 receiver->DeleteAndReplaceWith(NULL); |
8805 check->DeleteAndReplaceWith(NULL); | 8863 check->DeleteAndReplaceWith(NULL); |
8806 environment()->SetExpressionStackAt(receiver_index, function); | 8864 environment()->SetExpressionStackAt(receiver_index, function); |
8807 HInstruction* call = PreProcessCall( | 8865 HInstruction* call = PreProcessCall( |
8808 new(zone()) HCallNew(context, function, argument_count)); | 8866 new(zone()) HCallNew(context, function, argument_count)); |
8809 call->set_position(expr->position()); | 8867 call->set_position(expr->position()); |
8810 return ast_context()->ReturnInstruction(call, expr->id()); | 8868 return ast_context()->ReturnInstruction(call, expr->id()); |
8811 } else { | 8869 } else { |
8812 // The constructor function is both an operand to the instruction and an | 8870 // The constructor function is both an operand to the instruction and an |
8813 // argument to the construct call. | 8871 // argument to the construct call. |
(...skipping 2684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11498 } | 11556 } |
11499 } | 11557 } |
11500 | 11558 |
11501 #ifdef DEBUG | 11559 #ifdef DEBUG |
11502 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11560 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
11503 if (allocator_ != NULL) allocator_->Verify(); | 11561 if (allocator_ != NULL) allocator_->Verify(); |
11504 #endif | 11562 #endif |
11505 } | 11563 } |
11506 | 11564 |
11507 } } // namespace v8::internal | 11565 } } // namespace v8::internal |
OLD | NEW |