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 5644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5655 AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map)); | 5655 AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map)); |
5656 } | 5656 } |
5657 if (!expr->holder().is_null()) { | 5657 if (!expr->holder().is_null()) { |
5658 AddInstruction(new(zone()) HCheckPrototypeMaps( | 5658 AddInstruction(new(zone()) HCheckPrototypeMaps( |
5659 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), | 5659 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), |
5660 expr->holder())); | 5660 expr->holder())); |
5661 } | 5661 } |
5662 } | 5662 } |
5663 | 5663 |
5664 | 5664 |
5665 class FunctionSorter { | |
5666 public: | |
5667 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } | |
5668 FunctionSorter(int index, int ticks, int ast_length, int src_length) | |
5669 : index_(index), | |
5670 ticks_(ticks), | |
5671 ast_length_(ast_length), | |
5672 src_length_(src_length) { } | |
5673 | |
5674 int index() const { return index_; } | |
5675 int ticks() const { return ticks_; } | |
5676 int ast_length() const { return ast_length_; } | |
5677 int src_length() const { return src_length_; } | |
5678 | |
5679 private: | |
5680 int index_; | |
5681 int ticks_; | |
5682 int ast_length_; | |
5683 int src_length_; | |
5684 }; | |
5685 | |
5686 | |
5687 static int CompareHotness(void const* a, void const* b) { | |
5688 FunctionSorter const* function1 = reinterpret_cast<FunctionSorter const*>(a); | |
5689 FunctionSorter const* function2 = reinterpret_cast<FunctionSorter const*>(b); | |
5690 int diff = function1->ticks() - function2->ticks(); | |
5691 if (diff != 0) return -diff; | |
5692 diff = function1->ast_length() - function2->ast_length(); | |
5693 if (diff != 0) return diff; | |
5694 return function1->src_length() - function2->src_length(); | |
5695 } | |
5696 | |
5697 | |
5698 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 5665 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
5699 HValue* receiver, | 5666 HValue* receiver, |
5700 SmallMapList* types, | 5667 SmallMapList* types, |
5701 Handle<String> name) { | 5668 Handle<String> name) { |
5702 // TODO(ager): We should recognize when the prototype chains for different | 5669 // TODO(ager): We should recognize when the prototype chains for different |
5703 // maps are identical. In that case we can avoid repeatedly generating the | 5670 // maps are identical. In that case we can avoid repeatedly generating the |
5704 // same prototype map checks. | 5671 // same prototype map checks. |
5705 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 5672 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 5673 int count = 0; |
5706 HBasicBlock* join = NULL; | 5674 HBasicBlock* join = NULL; |
5707 FunctionSorter order[kMaxCallPolymorphism]; | 5675 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { |
5708 int ordered_functions = 0; | |
5709 for (int i = 0; | |
5710 i < types->length() && ordered_functions < kMaxCallPolymorphism; | |
5711 ++i) { | |
5712 Handle<Map> map = types->at(i); | 5676 Handle<Map> map = types->at(i); |
5713 if (expr->ComputeTarget(map, name)) { | 5677 if (expr->ComputeTarget(map, name)) { |
5714 order[ordered_functions++] = | 5678 if (count == 0) { |
5715 FunctionSorter(i, | 5679 // Only needed once. |
5716 expr->target()->shared()->code()->profiler_ticks(), | 5680 AddInstruction(new(zone()) HCheckNonSmi(receiver)); |
5717 InliningAstSize(expr->target()), | 5681 join = graph()->CreateBasicBlock(); |
5718 expr->target()->shared()->SourceSize()); | 5682 } |
| 5683 ++count; |
| 5684 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5685 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5686 HCompareMap* compare = |
| 5687 new(zone()) HCompareMap(receiver, map, if_true, if_false); |
| 5688 current_block()->Finish(compare); |
| 5689 |
| 5690 set_current_block(if_true); |
| 5691 AddCheckConstantFunction(expr, receiver, map, false); |
| 5692 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 5693 PrintF("Trying to inline the polymorphic call to %s\n", |
| 5694 *name->ToCString()); |
| 5695 } |
| 5696 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
| 5697 // Trying to inline will signal that we should bailout from the |
| 5698 // entire compilation by setting stack overflow on the visitor. |
| 5699 if (HasStackOverflow()) return; |
| 5700 } else { |
| 5701 HCallConstantFunction* call = |
| 5702 new(zone()) HCallConstantFunction(expr->target(), argument_count); |
| 5703 call->set_position(expr->position()); |
| 5704 PreProcessCall(call); |
| 5705 AddInstruction(call); |
| 5706 if (!ast_context()->IsEffect()) Push(call); |
| 5707 } |
| 5708 |
| 5709 if (current_block() != NULL) current_block()->Goto(join); |
| 5710 set_current_block(if_false); |
5719 } | 5711 } |
5720 } | 5712 } |
5721 | 5713 |
5722 qsort(reinterpret_cast<void*>(&order[0]), | |
5723 ordered_functions, | |
5724 sizeof(order[0]), | |
5725 &CompareHotness); | |
5726 | |
5727 for (int fn = 0; fn < ordered_functions; ++fn) { | |
5728 int i = order[fn].index(); | |
5729 Handle<Map> map = types->at(i); | |
5730 if (fn == 0) { | |
5731 // Only needed once. | |
5732 AddInstruction(new(zone()) HCheckNonSmi(receiver)); | |
5733 join = graph()->CreateBasicBlock(); | |
5734 } | |
5735 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
5736 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
5737 HCompareMap* compare = | |
5738 new(zone()) HCompareMap(receiver, map, if_true, if_false); | |
5739 current_block()->Finish(compare); | |
5740 | |
5741 set_current_block(if_true); | |
5742 expr->ComputeTarget(map, name); | |
5743 AddCheckConstantFunction(expr, receiver, map, false); | |
5744 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | |
5745 Handle<JSFunction> caller = info()->closure(); | |
5746 SmartArrayPointer<char> caller_name = | |
5747 caller->shared()->DebugName()->ToCString(); | |
5748 PrintF("Trying to inline the polymorphic call to %s from %s\n", | |
5749 *name->ToCString(), | |
5750 *caller_name); | |
5751 } | |
5752 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | |
5753 // Trying to inline will signal that we should bailout from the | |
5754 // entire compilation by setting stack overflow on the visitor. | |
5755 if (HasStackOverflow()) return; | |
5756 } else { | |
5757 HCallConstantFunction* call = | |
5758 new(zone()) HCallConstantFunction(expr->target(), argument_count); | |
5759 call->set_position(expr->position()); | |
5760 PreProcessCall(call); | |
5761 AddInstruction(call); | |
5762 if (!ast_context()->IsEffect()) Push(call); | |
5763 } | |
5764 | |
5765 if (current_block() != NULL) current_block()->Goto(join); | |
5766 set_current_block(if_false); | |
5767 } | |
5768 | |
5769 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5714 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5770 // know about and do not want to handle ones we've never seen. Otherwise | 5715 // know about and do not want to handle ones we've never seen. Otherwise |
5771 // use a generic IC. | 5716 // use a generic IC. |
5772 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 5717 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
5773 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 5718 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
5774 } else { | 5719 } else { |
5775 HValue* context = environment()->LookupContext(); | 5720 HValue* context = environment()->LookupContext(); |
5776 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); | 5721 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); |
5777 call->set_position(expr->position()); | 5722 call->set_position(expr->position()); |
5778 PreProcessCall(call); | 5723 PreProcessCall(call); |
5779 | 5724 |
5780 if (join != NULL) { | 5725 if (join != NULL) { |
5781 AddInstruction(call); | 5726 AddInstruction(call); |
5782 if (!ast_context()->IsEffect()) Push(call); | 5727 if (!ast_context()->IsEffect()) Push(call); |
(...skipping 28 matching lines...) Expand all Loading... |
5811 if (reason == NULL) { | 5756 if (reason == NULL) { |
5812 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 5757 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
5813 } else { | 5758 } else { |
5814 PrintF("Did not inline %s called from %s (%s).\n", | 5759 PrintF("Did not inline %s called from %s (%s).\n", |
5815 *target_name, *caller_name, reason); | 5760 *target_name, *caller_name, reason); |
5816 } | 5761 } |
5817 } | 5762 } |
5818 } | 5763 } |
5819 | 5764 |
5820 | 5765 |
5821 static const int kNotInlinable = 1000000000; | 5766 bool HGraphBuilder::TryInline(CallKind call_kind, |
5822 | 5767 Handle<JSFunction> target, |
5823 | 5768 ZoneList<Expression*>* arguments, |
5824 int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) { | 5769 HValue* receiver, |
5825 if (!FLAG_use_inlining) return kNotInlinable; | 5770 int ast_id, |
| 5771 int return_id, |
| 5772 ReturnHandlingFlag return_handling) { |
| 5773 if (!FLAG_use_inlining) return false; |
5826 | 5774 |
5827 // Precondition: call is monomorphic and we have found a target with the | 5775 // Precondition: call is monomorphic and we have found a target with the |
5828 // appropriate arity. | 5776 // appropriate arity. |
5829 Handle<JSFunction> caller = info()->closure(); | 5777 Handle<JSFunction> caller = info()->closure(); |
5830 Handle<SharedFunctionInfo> target_shared(target->shared()); | 5778 Handle<SharedFunctionInfo> target_shared(target->shared()); |
5831 | 5779 |
5832 // Do a quick check on source code length to avoid parsing large | 5780 // Do a quick check on source code length to avoid parsing large |
5833 // inlining candidates. | 5781 // inlining candidates. |
5834 if (target_shared->SourceSize() > | 5782 if (target_shared->SourceSize() > |
5835 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { | 5783 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { |
5836 TraceInline(target, caller, "target text too big"); | 5784 TraceInline(target, caller, "target text too big"); |
5837 return kNotInlinable; | 5785 return false; |
5838 } | 5786 } |
5839 | 5787 |
5840 // Target must be inlineable. | 5788 // Target must be inlineable. |
5841 if (!target->IsInlineable()) { | 5789 if (!target->IsInlineable()) { |
5842 TraceInline(target, caller, "target not inlineable"); | 5790 TraceInline(target, caller, "target not inlineable"); |
5843 return kNotInlinable; | 5791 return false; |
5844 } | 5792 } |
5845 if (target_shared->dont_inline() || target_shared->dont_optimize()) { | 5793 if (target_shared->dont_inline() || target_shared->dont_optimize()) { |
5846 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 5794 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
5847 return kNotInlinable; | 5795 return false; |
5848 } | 5796 } |
5849 | 5797 |
5850 int nodes_added = target_shared->ast_node_count(); | 5798 int nodes_added = target_shared->ast_node_count(); |
5851 return nodes_added; | |
5852 } | |
5853 | |
5854 | |
5855 bool HGraphBuilder::TryInline(CallKind call_kind, | |
5856 Handle<JSFunction> target, | |
5857 ZoneList<Expression*>* arguments, | |
5858 HValue* receiver, | |
5859 int ast_id, | |
5860 int return_id, | |
5861 ReturnHandlingFlag return_handling) { | |
5862 int nodes_added = InliningAstSize(target); | |
5863 if (nodes_added == kNotInlinable) return false; | |
5864 | |
5865 Handle<JSFunction> caller = info()->closure(); | |
5866 | |
5867 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 5799 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
5868 TraceInline(target, caller, "target AST is too large [early]"); | 5800 TraceInline(target, caller, "target AST is too large [early]"); |
5869 return false; | 5801 return false; |
5870 } | 5802 } |
5871 | 5803 |
5872 Handle<SharedFunctionInfo> target_shared(target->shared()); | |
5873 | |
5874 #if !defined(V8_TARGET_ARCH_IA32) | 5804 #if !defined(V8_TARGET_ARCH_IA32) |
5875 // Target must be able to use caller's context. | 5805 // Target must be able to use caller's context. |
5876 CompilationInfo* outer_info = info(); | 5806 CompilationInfo* outer_info = info(); |
5877 if (target->context() != outer_info->closure()->context() || | 5807 if (target->context() != outer_info->closure()->context() || |
5878 outer_info->scope()->contains_with() || | 5808 outer_info->scope()->contains_with() || |
5879 outer_info->scope()->num_heap_slots() > 0) { | 5809 outer_info->scope()->num_heap_slots() > 0) { |
5880 TraceInline(target, caller, "target requires context change"); | 5810 TraceInline(target, caller, "target requires context change"); |
5881 return false; | 5811 return false; |
5882 } | 5812 } |
5883 #endif | 5813 #endif |
(...skipping 2976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8860 } | 8790 } |
8861 } | 8791 } |
8862 | 8792 |
8863 #ifdef DEBUG | 8793 #ifdef DEBUG |
8864 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8794 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
8865 if (allocator_ != NULL) allocator_->Verify(); | 8795 if (allocator_ != NULL) allocator_->Verify(); |
8866 #endif | 8796 #endif |
8867 } | 8797 } |
8868 | 8798 |
8869 } } // namespace v8::internal | 8799 } } // namespace v8::internal |
OLD | NEW |