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 678 matching lines...) Loading... |
689 | 689 |
690 HGraph::HGraph(CompilationInfo* info) | 690 HGraph::HGraph(CompilationInfo* info) |
691 : isolate_(info->isolate()), | 691 : isolate_(info->isolate()), |
692 next_block_id_(0), | 692 next_block_id_(0), |
693 entry_block_(NULL), | 693 entry_block_(NULL), |
694 blocks_(8, info->zone()), | 694 blocks_(8, info->zone()), |
695 values_(16, info->zone()), | 695 values_(16, info->zone()), |
696 phi_list_(NULL), | 696 phi_list_(NULL), |
697 info_(info), | 697 info_(info), |
698 zone_(info->zone()), | 698 zone_(info->zone()), |
699 is_recursive_(false) { | 699 is_recursive_(false), |
| 700 use_optimistic_licm_(false), |
| 701 type_change_checksum_(0) { |
700 start_environment_ = | 702 start_environment_ = |
701 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 703 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
702 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 704 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
703 entry_block_ = CreateBasicBlock(); | 705 entry_block_ = CreateBasicBlock(); |
704 entry_block_->SetInitialEnvironment(start_environment_); | 706 entry_block_->SetInitialEnvironment(start_environment_); |
705 } | 707 } |
706 | 708 |
707 | 709 |
708 HBasicBlock* HGraph::CreateBasicBlock() { | 710 HBasicBlock* HGraph::CreateBasicBlock() { |
709 HBasicBlock* result = new(zone()) HBasicBlock(this); | 711 HBasicBlock* result = new(zone()) HBasicBlock(this); |
(...skipping 1182 matching lines...) Loading... |
1892 #endif | 1894 #endif |
1893 size_t string_len = strlen(underlying_buffer) + 1; | 1895 size_t string_len = strlen(underlying_buffer) + 1; |
1894 ASSERT(string_len <= sizeof(underlying_buffer)); | 1896 ASSERT(string_len <= sizeof(underlying_buffer)); |
1895 char* result = new char[strlen(underlying_buffer) + 1]; | 1897 char* result = new char[strlen(underlying_buffer) + 1]; |
1896 memcpy(result, underlying_buffer, string_len); | 1898 memcpy(result, underlying_buffer, string_len); |
1897 return SmartArrayPointer<char>(result); | 1899 return SmartArrayPointer<char>(result); |
1898 } | 1900 } |
1899 | 1901 |
1900 | 1902 |
1901 void HGlobalValueNumberer::LoopInvariantCodeMotion() { | 1903 void HGlobalValueNumberer::LoopInvariantCodeMotion() { |
| 1904 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", |
| 1905 graph_->use_optimistic_licm() ? "yes" : "no"); |
1902 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1906 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
1903 HBasicBlock* block = graph_->blocks()->at(i); | 1907 HBasicBlock* block = graph_->blocks()->at(i); |
1904 if (block->IsLoopHeader()) { | 1908 if (block->IsLoopHeader()) { |
1905 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 1909 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; |
1906 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", | 1910 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", |
1907 block->block_id(), | 1911 block->block_id(), |
1908 *GetGVNFlagsString(side_effects)); | 1912 *GetGVNFlagsString(side_effects)); |
1909 | 1913 |
1910 GVNFlagSet accumulated_first_time_depends; | 1914 GVNFlagSet accumulated_first_time_depends; |
1911 GVNFlagSet accumulated_first_time_changes; | 1915 GVNFlagSet accumulated_first_time_changes; |
(...skipping 23 matching lines...) Loading... |
1935 while (instr != NULL) { | 1939 while (instr != NULL) { |
1936 HInstruction* next = instr->next(); | 1940 HInstruction* next = instr->next(); |
1937 bool hoisted = false; | 1941 bool hoisted = false; |
1938 if (instr->CheckFlag(HValue::kUseGVN)) { | 1942 if (instr->CheckFlag(HValue::kUseGVN)) { |
1939 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | 1943 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", |
1940 instr->id(), | 1944 instr->id(), |
1941 instr->Mnemonic(), | 1945 instr->Mnemonic(), |
1942 *GetGVNFlagsString(instr->gvn_flags()), | 1946 *GetGVNFlagsString(instr->gvn_flags()), |
1943 *GetGVNFlagsString(loop_kills)); | 1947 *GetGVNFlagsString(loop_kills)); |
1944 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 1948 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 1949 if (can_hoist && !graph()->use_optimistic_licm()) { |
| 1950 can_hoist = block->IsLoopSuccessorDominator(); |
| 1951 } |
1945 if (instr->IsTransitionElementsKind()) { | 1952 if (instr->IsTransitionElementsKind()) { |
1946 // It's possible to hoist transitions out of a loop as long as the | 1953 // It's possible to hoist transitions out of a loop as long as the |
1947 // hoisting wouldn't move the transition past an instruction that has a | 1954 // hoisting wouldn't move the transition past an instruction that has a |
1948 // DependsOn flag for anything it changes. | 1955 // DependsOn flag for anything it changes. |
1949 GVNFlagSet hoist_depends_blockers = | 1956 GVNFlagSet hoist_depends_blockers = |
1950 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); | 1957 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); |
1951 | 1958 |
1952 // In addition, the transition must not be hoisted above elements kind | 1959 // In addition, the transition must not be hoisted above elements kind |
1953 // changes, or if the transition is destructive to the elements buffer, | 1960 // changes, or if the transition is destructive to the elements buffer, |
1954 // changes to array pointer or array contents. | 1961 // changes to array pointer or array contents. |
(...skipping 1124 matching lines...) Loading... |
3079 new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); | 3086 new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); |
3080 | 3087 |
3081 VisitStatements(info()->function()->body()); | 3088 VisitStatements(info()->function()->body()); |
3082 if (HasStackOverflow()) return NULL; | 3089 if (HasStackOverflow()) return NULL; |
3083 | 3090 |
3084 if (current_block() != NULL) { | 3091 if (current_block() != NULL) { |
3085 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); | 3092 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); |
3086 current_block()->FinishExit(instr); | 3093 current_block()->FinishExit(instr); |
3087 set_current_block(NULL); | 3094 set_current_block(NULL); |
3088 } | 3095 } |
| 3096 |
| 3097 // If the checksum of the number of type info changes is the same as the |
| 3098 // last time this function was compiled, then this recompile is likely not |
| 3099 // due to missing/inadequate type feedback, but rather too aggressive |
| 3100 // optimization. Disable optimistic LICM in that case. |
| 3101 Handle<Code> unoptimized_code(info()->shared_info()->code()); |
| 3102 ASSERT(unoptimized_code->kind() == Code::FUNCTION); |
| 3103 Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); |
| 3104 Handle<TypeFeedbackInfo> type_info( |
| 3105 Handle<TypeFeedbackInfo>::cast(maybe_type_info)); |
| 3106 int checksum = type_info->own_type_change_checksum(); |
| 3107 int composite_checksum = graph()->update_type_change_checksum(checksum); |
| 3108 graph()->set_use_optimistic_licm( |
| 3109 !type_info->matches_inlined_type_change_checksum(composite_checksum)); |
| 3110 type_info->set_inlined_type_change_checksum(composite_checksum); |
3089 } | 3111 } |
3090 | 3112 |
3091 return graph(); | 3113 return graph(); |
3092 } | 3114 } |
3093 | 3115 |
3094 bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { | 3116 bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { |
3095 *bailout_reason = SmartArrayPointer<char>(); | 3117 *bailout_reason = SmartArrayPointer<char>(); |
3096 OrderBlocks(); | 3118 OrderBlocks(); |
3097 AssignDominators(); | 3119 AssignDominators(); |
3098 | 3120 |
(...skipping 3715 matching lines...) Loading... |
6814 target_shared); | 6836 target_shared); |
6815 } | 6837 } |
6816 | 6838 |
6817 // ---------------------------------------------------------------- | 6839 // ---------------------------------------------------------------- |
6818 // After this point, we've made a decision to inline this function (so | 6840 // After this point, we've made a decision to inline this function (so |
6819 // TryInline should always return true). | 6841 // TryInline should always return true). |
6820 | 6842 |
6821 // Save the pending call context and type feedback oracle. Set up new ones | 6843 // Save the pending call context and type feedback oracle. Set up new ones |
6822 // for the inlined function. | 6844 // for the inlined function. |
6823 ASSERT(target_shared->has_deoptimization_support()); | 6845 ASSERT(target_shared->has_deoptimization_support()); |
| 6846 Handle<Code> unoptimized_code(target_shared->code()); |
6824 TypeFeedbackOracle target_oracle( | 6847 TypeFeedbackOracle target_oracle( |
6825 Handle<Code>(target_shared->code()), | 6848 unoptimized_code, |
6826 Handle<Context>(target->context()->native_context()), | 6849 Handle<Context>(target->context()->native_context()), |
6827 isolate(), | 6850 isolate(), |
6828 zone()); | 6851 zone()); |
6829 // The function state is new-allocated because we need to delete it | 6852 // The function state is new-allocated because we need to delete it |
6830 // in two different places. | 6853 // in two different places. |
6831 FunctionState* target_state = new FunctionState( | 6854 FunctionState* target_state = new FunctionState( |
6832 this, &target_info, &target_oracle, inlining_kind); | 6855 this, &target_info, &target_oracle, inlining_kind); |
6833 | 6856 |
6834 HConstant* undefined = graph()->GetConstantUndefined(); | 6857 HConstant* undefined = graph()->GetConstantUndefined(); |
6835 HEnvironment* inner_env = | 6858 HEnvironment* inner_env = |
(...skipping 59 matching lines...) Loading... |
6895 TraceInline(target, caller, "inline graph construction failed"); | 6918 TraceInline(target, caller, "inline graph construction failed"); |
6896 target_shared->DisableOptimization(); | 6919 target_shared->DisableOptimization(); |
6897 inline_bailout_ = true; | 6920 inline_bailout_ = true; |
6898 delete target_state; | 6921 delete target_state; |
6899 return true; | 6922 return true; |
6900 } | 6923 } |
6901 | 6924 |
6902 // Update inlined nodes count. | 6925 // Update inlined nodes count. |
6903 inlined_count_ += nodes_added; | 6926 inlined_count_ += nodes_added; |
6904 | 6927 |
| 6928 ASSERT(unoptimized_code->kind() == Code::FUNCTION); |
| 6929 Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); |
| 6930 Handle<TypeFeedbackInfo> type_info( |
| 6931 Handle<TypeFeedbackInfo>::cast(maybe_type_info)); |
| 6932 graph()->update_type_change_checksum(type_info->own_type_change_checksum()); |
| 6933 |
6905 TraceInline(target, caller, NULL); | 6934 TraceInline(target, caller, NULL); |
6906 | 6935 |
6907 if (current_block() != NULL) { | 6936 if (current_block() != NULL) { |
6908 FunctionState* state = function_state(); | 6937 FunctionState* state = function_state(); |
6909 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { | 6938 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { |
6910 // Falling off the end of an inlined construct call. In a test context the | 6939 // Falling off the end of an inlined construct call. In a test context the |
6911 // return value will always evaluate to true, in a value context the | 6940 // return value will always evaluate to true, in a value context the |
6912 // return value is the newly allocated receiver. | 6941 // return value is the newly allocated receiver. |
6913 if (call_context()->IsTest()) { | 6942 if (call_context()->IsTest()) { |
6914 current_block()->Goto(inlined_test_context()->if_true(), state); | 6943 current_block()->Goto(inlined_test_context()->if_true(), state); |
(...skipping 2782 matching lines...) Loading... |
9697 } | 9726 } |
9698 } | 9727 } |
9699 | 9728 |
9700 #ifdef DEBUG | 9729 #ifdef DEBUG |
9701 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 9730 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
9702 if (allocator_ != NULL) allocator_->Verify(); | 9731 if (allocator_ != NULL) allocator_->Verify(); |
9703 #endif | 9732 #endif |
9704 } | 9733 } |
9705 | 9734 |
9706 } } // namespace v8::internal | 9735 } } // namespace v8::internal |
OLD | NEW |