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

Side by Side Diff: src/hydrogen.cc

Issue 10270032: Sort functions when doing megamorphic dispatch/inlining so their (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698