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 | |
5665 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 5698 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
5666 HValue* receiver, | 5699 HValue* receiver, |
5667 SmallMapList* types, | 5700 SmallMapList* types, |
5668 Handle<String> name) { | 5701 Handle<String> name) { |
5669 // TODO(ager): We should recognize when the prototype chains for different | 5702 // TODO(ager): We should recognize when the prototype chains for different |
5670 // maps are identical. In that case we can avoid repeatedly generating the | 5703 // maps are identical. In that case we can avoid repeatedly generating the |
5671 // same prototype map checks. | 5704 // same prototype map checks. |
5672 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 5705 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
5673 int count = 0; | |
5674 HBasicBlock* join = NULL; | 5706 HBasicBlock* join = NULL; |
5675 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { | 5707 FunctionSorter order[kMaxCallPolymorphism]; |
5708 int ordered_functions = 0; | |
5709 for (int i = 0; | |
5710 i < types->length() && ordered_functions < kMaxCallPolymorphism; | |
5711 ++i) { | |
5676 Handle<Map> map = types->at(i); | 5712 Handle<Map> map = types->at(i); |
5677 if (expr->ComputeTarget(map, name)) { | 5713 if (expr->ComputeTarget(map, name)) { |
5678 if (count == 0) { | 5714 order[ordered_functions++] = |
5679 // Only needed once. | 5715 FunctionSorter(i, |
5680 AddInstruction(new(zone()) HCheckNonSmi(receiver)); | 5716 expr->target()->shared()->code()->profiler_ticks(), |
5681 join = graph()->CreateBasicBlock(); | 5717 InliningAstSize(expr->target()), |
Michael Starzinger
2012/05/02 08:10:35
Could we just use "expr->target()->shared()->ast_n
Erik Corry
2012/05/08 12:13:38
The reason I don't do this is that we already have
| |
5682 } | 5718 expr->target()->shared()->SourceSize()); |
5683 ++count; | 5719 } |
5684 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5720 } |
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 | 5721 |
5690 set_current_block(if_true); | 5722 qsort(reinterpret_cast<void*>(&order[0]), |
5691 AddCheckConstantFunction(expr, receiver, map, false); | 5723 ordered_functions, |
5692 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 5724 sizeof(order[0]), |
5693 PrintF("Trying to inline the polymorphic call to %s\n", | 5725 &CompareHotness); |
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 | 5726 |
5709 if (current_block() != NULL) current_block()->Goto(join); | 5727 for (int fn = 0; fn < ordered_functions; ++fn) { |
5710 set_current_block(if_false); | 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(); | |
5711 } | 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); | |
5712 } | 5767 } |
5713 | 5768 |
5714 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5769 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5715 // know about and do not want to handle ones we've never seen. Otherwise | 5770 // know about and do not want to handle ones we've never seen. Otherwise |
5716 // use a generic IC. | 5771 // use a generic IC. |
5717 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5772 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
5718 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 5773 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
5719 } else { | 5774 } else { |
5720 HValue* context = environment()->LookupContext(); | 5775 HValue* context = environment()->LookupContext(); |
5721 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); | 5776 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); |
5722 call->set_position(expr->position()); | 5777 call->set_position(expr->position()); |
5723 PreProcessCall(call); | 5778 PreProcessCall(call); |
5724 | 5779 |
5725 if (join != NULL) { | 5780 if (join != NULL) { |
5726 AddInstruction(call); | 5781 AddInstruction(call); |
5727 if (!ast_context()->IsEffect()) Push(call); | 5782 if (!ast_context()->IsEffect()) Push(call); |
(...skipping 28 matching lines...) Expand all Loading... | |
5756 if (reason == NULL) { | 5811 if (reason == NULL) { |
5757 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 5812 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
5758 } else { | 5813 } else { |
5759 PrintF("Did not inline %s called from %s (%s).\n", | 5814 PrintF("Did not inline %s called from %s (%s).\n", |
5760 *target_name, *caller_name, reason); | 5815 *target_name, *caller_name, reason); |
5761 } | 5816 } |
5762 } | 5817 } |
5763 } | 5818 } |
5764 | 5819 |
5765 | 5820 |
5766 bool HGraphBuilder::TryInline(CallKind call_kind, | 5821 static const int kNotInlinable = 1000000000; |
5767 Handle<JSFunction> target, | 5822 |
5768 ZoneList<Expression*>* arguments, | 5823 |
5769 HValue* receiver, | 5824 int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) { |
5770 int ast_id, | 5825 if (!FLAG_use_inlining) return kNotInlinable; |
5771 int return_id, | |
5772 ReturnHandlingFlag return_handling) { | |
5773 if (!FLAG_use_inlining) return false; | |
5774 | 5826 |
5775 // Precondition: call is monomorphic and we have found a target with the | 5827 // Precondition: call is monomorphic and we have found a target with the |
5776 // appropriate arity. | 5828 // appropriate arity. |
5777 Handle<JSFunction> caller = info()->closure(); | 5829 Handle<JSFunction> caller = info()->closure(); |
5778 Handle<SharedFunctionInfo> target_shared(target->shared()); | 5830 Handle<SharedFunctionInfo> target_shared(target->shared()); |
5779 | 5831 |
5780 // Do a quick check on source code length to avoid parsing large | 5832 // Do a quick check on source code length to avoid parsing large |
5781 // inlining candidates. | 5833 // inlining candidates. |
5782 if (target_shared->SourceSize() > | 5834 if (target_shared->SourceSize() > |
5783 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { | 5835 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { |
5784 TraceInline(target, caller, "target text too big"); | 5836 TraceInline(target, caller, "target text too big"); |
5785 return false; | 5837 return kNotInlinable; |
5786 } | 5838 } |
5787 | 5839 |
5788 // Target must be inlineable. | 5840 // Target must be inlineable. |
5789 if (!target->IsInlineable()) { | 5841 if (!target->IsInlineable()) { |
5790 TraceInline(target, caller, "target not inlineable"); | 5842 TraceInline(target, caller, "target not inlineable"); |
5791 return false; | 5843 return kNotInlinable; |
5792 } | 5844 } |
5793 if (target_shared->dont_inline() || target_shared->dont_optimize()) { | 5845 if (target_shared->dont_inline() || target_shared->dont_optimize()) { |
5794 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 5846 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
5795 return false; | 5847 return kNotInlinable; |
5796 } | 5848 } |
5797 | 5849 |
5798 int nodes_added = target_shared->ast_node_count(); | 5850 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 | |
5799 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 5867 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
5800 TraceInline(target, caller, "target AST is too large [early]"); | 5868 TraceInline(target, caller, "target AST is too large [early]"); |
5801 return false; | 5869 return false; |
5802 } | 5870 } |
5803 | 5871 |
5872 Handle<SharedFunctionInfo> target_shared(target->shared()); | |
5873 | |
5804 #if !defined(V8_TARGET_ARCH_IA32) | 5874 #if !defined(V8_TARGET_ARCH_IA32) |
5805 // Target must be able to use caller's context. | 5875 // Target must be able to use caller's context. |
5806 CompilationInfo* outer_info = info(); | 5876 CompilationInfo* outer_info = info(); |
5807 if (target->context() != outer_info->closure()->context() || | 5877 if (target->context() != outer_info->closure()->context() || |
5808 outer_info->scope()->contains_with() || | 5878 outer_info->scope()->contains_with() || |
5809 outer_info->scope()->num_heap_slots() > 0) { | 5879 outer_info->scope()->num_heap_slots() > 0) { |
5810 TraceInline(target, caller, "target requires context change"); | 5880 TraceInline(target, caller, "target requires context change"); |
5811 return false; | 5881 return false; |
5812 } | 5882 } |
5813 #endif | 5883 #endif |
(...skipping 2976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8790 } | 8860 } |
8791 } | 8861 } |
8792 | 8862 |
8793 #ifdef DEBUG | 8863 #ifdef DEBUG |
8794 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8864 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
8795 if (allocator_ != NULL) allocator_->Verify(); | 8865 if (allocator_ != NULL) allocator_->Verify(); |
8796 #endif | 8866 #endif |
8797 } | 8867 } |
8798 | 8868 |
8799 } } // namespace v8::internal | 8869 } } // namespace v8::internal |
OLD | NEW |