Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler.h" | 5 #include "src/compiler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "src/ast/ast-numbering.h" | 9 #include "src/ast/ast-numbering.h" |
| 10 #include "src/ast/prettyprinter.h" | 10 #include "src/ast/prettyprinter.h" |
| 11 #include "src/ast/scopeinfo.h" | 11 #include "src/ast/scopeinfo.h" |
| 12 #include "src/ast/scopes.h" | 12 #include "src/ast/scopes.h" |
| 13 #include "src/bootstrapper.h" | 13 #include "src/bootstrapper.h" |
| 14 #include "src/codegen.h" | 14 #include "src/codegen.h" |
| 15 #include "src/compilation-cache.h" | 15 #include "src/compilation-cache.h" |
| 16 #include "src/compiler/pipeline.h" | 16 #include "src/compiler/pipeline.h" |
| 17 #include "src/crankshaft/hydrogen.h" | 17 #include "src/crankshaft/hydrogen.h" |
| 18 #include "src/debug/debug.h" | 18 #include "src/debug/debug.h" |
| 19 #include "src/debug/liveedit.h" | 19 #include "src/debug/liveedit.h" |
| 20 #include "src/deoptimizer.h" | 20 #include "src/deoptimizer.h" |
| 21 #include "src/frames-inl.h" | |
| 21 #include "src/full-codegen/full-codegen.h" | 22 #include "src/full-codegen/full-codegen.h" |
| 22 #include "src/interpreter/interpreter.h" | 23 #include "src/interpreter/interpreter.h" |
| 23 #include "src/isolate-inl.h" | 24 #include "src/isolate-inl.h" |
| 24 #include "src/log-inl.h" | 25 #include "src/log-inl.h" |
| 25 #include "src/messages.h" | 26 #include "src/messages.h" |
| 26 #include "src/parsing/parser.h" | 27 #include "src/parsing/parser.h" |
| 27 #include "src/parsing/rewriter.h" | 28 #include "src/parsing/rewriter.h" |
| 28 #include "src/parsing/scanner-character-streams.h" | 29 #include "src/parsing/scanner-character-streams.h" |
| 29 #include "src/profiler/cpu-profiler.h" | 30 #include "src/profiler/cpu-profiler.h" |
| 30 #include "src/runtime-profiler.h" | 31 #include "src/runtime-profiler.h" |
| (...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 583 VMState<COMPILER> state(info->isolate()); | 584 VMState<COMPILER> state(info->isolate()); |
| 584 PostponeInterruptsScope postpone(info->isolate()); | 585 PostponeInterruptsScope postpone(info->isolate()); |
| 585 | 586 |
| 586 // Parse and update CompilationInfo with the results. | 587 // Parse and update CompilationInfo with the results. |
| 587 if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>(); | 588 if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>(); |
| 588 Handle<SharedFunctionInfo> shared = info->shared_info(); | 589 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 589 DCHECK_EQ(shared->language_mode(), info->literal()->language_mode()); | 590 DCHECK_EQ(shared->language_mode(), info->literal()->language_mode()); |
| 590 | 591 |
| 591 // Compile either unoptimized code or bytecode for the interpreter. | 592 // Compile either unoptimized code or bytecode for the interpreter. |
| 592 if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); | 593 if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); |
| 593 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); | |
| 594 | 594 |
| 595 // Update the shared function info with the scope info. | 595 // Update the shared function info with the scope info. |
| 596 InstallSharedScopeInfo(info, shared); | 596 InstallSharedScopeInfo(info, shared); |
| 597 | 597 |
| 598 // Install compilation result on the shared function info | 598 // Install compilation result on the shared function info |
| 599 InstallSharedCompilationResult(info, shared); | 599 InstallSharedCompilationResult(info, shared); |
| 600 | 600 |
| 601 // Record the function compilation event. | |
| 602 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); | |
| 603 | |
| 601 return info->code(); | 604 return info->code(); |
| 602 } | 605 } |
| 603 | 606 |
| 604 MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap( | 607 MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap( |
| 605 Handle<JSFunction> function, BailoutId osr_ast_id) { | 608 Handle<JSFunction> function, BailoutId osr_ast_id) { |
| 606 Handle<SharedFunctionInfo> shared(function->shared()); | 609 Handle<SharedFunctionInfo> shared(function->shared()); |
| 607 DisallowHeapAllocation no_gc; | 610 DisallowHeapAllocation no_gc; |
| 608 CodeAndLiterals cached = shared->SearchOptimizedCodeMap( | 611 CodeAndLiterals cached = shared->SearchOptimizedCodeMap( |
| 609 function->context()->native_context(), osr_ast_id); | 612 function->context()->native_context(), osr_ast_id); |
| 610 if (cached.code != nullptr) { | 613 if (cached.code != nullptr) { |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 PrintF("[found optimized code for "); | 801 PrintF("[found optimized code for "); |
| 799 function->ShortPrint(); | 802 function->ShortPrint(); |
| 800 if (!osr_ast_id.IsNone()) { | 803 if (!osr_ast_id.IsNone()) { |
| 801 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); | 804 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); |
| 802 } | 805 } |
| 803 PrintF("]\n"); | 806 PrintF("]\n"); |
| 804 } | 807 } |
| 805 return cached_code; | 808 return cached_code; |
| 806 } | 809 } |
| 807 | 810 |
| 808 DCHECK(AllowCompilation::IsAllowed(isolate)); | 811 // Reset profiler ticks, function is no longer considered hot. |
| 809 | |
| 810 if (shared->is_compiled()) { | 812 if (shared->is_compiled()) { |
| 811 shared->code()->set_profiler_ticks(0); | 813 shared->code()->set_profiler_ticks(0); |
| 812 } | 814 } |
| 813 | 815 |
| 814 // TODO(mstarzinger): We cannot properly deserialize a scope chain containing | 816 // TODO(mstarzinger): We cannot properly deserialize a scope chain containing |
| 815 // an eval scope and hence would fail at parsing the eval source again. | 817 // an eval scope and hence would fail at parsing the eval source again. |
| 816 if (shared->disable_optimization_reason() == kEval) { | 818 if (shared->disable_optimization_reason() == kEval) { |
| 817 return MaybeHandle<Code>(); | 819 return MaybeHandle<Code>(); |
| 818 } | 820 } |
| 819 | 821 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 853 } | 855 } |
| 854 } else { | 856 } else { |
| 855 info->set_osr_frame(osr_frame); | 857 info->set_osr_frame(osr_frame); |
| 856 if (GetOptimizedCodeNow(info.get())) return info->code(); | 858 if (GetOptimizedCodeNow(info.get())) return info->code(); |
| 857 } | 859 } |
| 858 | 860 |
| 859 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); | 861 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); |
| 860 return MaybeHandle<Code>(); | 862 return MaybeHandle<Code>(); |
| 861 } | 863 } |
| 862 | 864 |
| 865 class InterpreterActivationsFinder : public ThreadVisitor { | |
| 866 public: | |
| 867 SharedFunctionInfo* shared_; | |
| 868 bool has_activations_; | |
| 869 | |
| 870 explicit InterpreterActivationsFinder(SharedFunctionInfo* shared) | |
| 871 : shared_(shared), has_activations_(false) {} | |
| 872 | |
| 873 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | |
| 874 JavaScriptFrameIterator it(isolate, top); | |
| 875 for (; !it.done(); it.Advance()) { | |
|
rmcilroy
2016/04/22 10:02:57
Also done when "has_activations_" ?
Michael Starzinger
2016/04/22 10:47:45
Done.
| |
| 876 JavaScriptFrame* frame = it.frame(); | |
| 877 if (!frame->is_interpreted()) continue; | |
| 878 if (frame->function()->shared() == shared_) has_activations_ = true; | |
| 879 } | |
| 880 } | |
| 881 }; | |
| 882 | |
| 883 bool HasInterpreterActivations(Isolate* isolate, SharedFunctionInfo* shared) { | |
| 884 InterpreterActivationsFinder activations_finder(shared); | |
| 885 activations_finder.VisitThread(isolate, isolate->thread_local_top()); | |
| 886 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); | |
| 887 return activations_finder.has_activations_; | |
| 888 } | |
| 889 | |
| 890 MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { | |
| 891 Isolate* isolate = function->GetIsolate(); | |
| 892 VMState<COMPILER> state(isolate); | |
| 893 PostponeInterruptsScope postpone(isolate); | |
| 894 CompilationInfoWithZone info(function); | |
| 895 | |
| 896 // Reset profiler ticks, function is no longer considered hot. | |
| 897 if (function->shared()->HasBytecodeArray()) { | |
| 898 function->shared()->set_profiler_ticks(0); | |
| 899 } | |
| 900 | |
| 901 // TODO(4280): For now we do not switch to baseline code when the debugger | |
| 902 // might have created a copy of the bytecode with break slots. | |
|
rmcilroy
2016/04/22 10:02:57
Is this a TODO - I though we were planning to alwa
Michael Starzinger
2016/04/22 10:47:45
Done. I don't have a concrete answer on whether we
| |
| 903 if (function->shared()->HasDebugInfo()) { | |
| 904 return MaybeHandle<Code>(); | |
| 905 } | |
| 906 | |
| 907 // TODO(4280): For now we do not switch generators to baseline code because | |
| 908 // there might be suspended activations stored in generator objects on the | |
| 909 // heap. We could eventually go directly to TurboFan in this case. | |
| 910 if (function->shared()->is_generator()) { | |
| 911 return MaybeHandle<Code>(); | |
| 912 } | |
| 913 | |
| 914 // TODO(4280): For now we disable switching to baseline code in the presence | |
| 915 // of interpreter activations of the given function. The reasons are: | |
| 916 // 1) The debugger assumes each function is either full-code or bytecode. | |
| 917 // 2) The underlying bytecode is cleared below, breaking stack unwinding. | |
| 918 if (HasInterpreterActivations(isolate, function->shared())) { | |
| 919 if (FLAG_trace_opt) { | |
| 920 OFStream os(stdout); | |
| 921 os << "[unable to switch " << Brief(*function) << " due to activations]" | |
| 922 << std::endl; | |
| 923 } | |
| 924 return MaybeHandle<Code>(); | |
| 925 } | |
| 926 | |
| 927 if (FLAG_trace_opt) { | |
| 928 OFStream os(stdout); | |
| 929 os << "[switching method " << Brief(*function) << " to baseline code]" | |
| 930 << std::endl; | |
| 931 } | |
| 932 | |
| 933 // Parse and update CompilationInfo with the results. | |
| 934 if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>(); | |
| 935 Handle<SharedFunctionInfo> shared = info.shared_info(); | |
| 936 DCHECK_EQ(shared->language_mode(), info.literal()->language_mode()); | |
| 937 | |
| 938 // Compile unoptimized code using the full code generator. | |
|
rmcilroy
2016/04/22 10:02:57
/s/unoptimzed/baseline
Michael Starzinger
2016/04/22 10:47:45
Done.
| |
| 939 if (!Compiler::Analyze(info.parse_info()) || | |
| 940 !FullCodeGenerator::MakeCode(&info)) { | |
| 941 if (!isolate->has_pending_exception()) isolate->StackOverflow(); | |
| 942 return MaybeHandle<Code>(); | |
| 943 } | |
| 944 | |
| 945 // TODO(4280): For now we play it safe and remove the bytecode array when we | |
| 946 // switch to baseline code. We might consider keeping around the bytecode so | |
| 947 // that it can be used as the "source of truth" eventually. | |
| 948 shared->ClearBytecodeArray(); | |
| 949 | |
| 950 // Update the shared function info with the scope info. | |
| 951 InstallSharedScopeInfo(&info, shared); | |
| 952 | |
| 953 // Install compilation result on the shared function info | |
| 954 InstallSharedCompilationResult(&info, shared); | |
| 955 | |
| 956 // Record the function compilation event. | |
| 957 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &info); | |
| 958 | |
| 959 return info.code(); | |
| 960 } | |
| 961 | |
| 863 MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { | 962 MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { |
| 864 Isolate* isolate = function->GetIsolate(); | 963 Isolate* isolate = function->GetIsolate(); |
| 865 DCHECK(!isolate->has_pending_exception()); | 964 DCHECK(!isolate->has_pending_exception()); |
| 866 DCHECK(!function->is_compiled()); | 965 DCHECK(!function->is_compiled()); |
| 867 TimerEventScope<TimerEventCompileCode> compile_timer(isolate); | 966 TimerEventScope<TimerEventCompileCode> compile_timer(isolate); |
| 868 TRACE_EVENT0("v8", "V8.CompileCode"); | 967 TRACE_EVENT0("v8", "V8.CompileCode"); |
| 869 AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy()); | 968 AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy()); |
| 870 | 969 |
| 871 if (FLAG_turbo_cache_shared_code) { | 970 if (FLAG_turbo_cache_shared_code) { |
| 872 Handle<Code> cached_code; | 971 Handle<Code> cached_code; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1082 // Install code on closure. | 1181 // Install code on closure. |
| 1083 function->ReplaceCode(*code); | 1182 function->ReplaceCode(*code); |
| 1084 | 1183 |
| 1085 // Check postconditions on success. | 1184 // Check postconditions on success. |
| 1086 DCHECK(!isolate->has_pending_exception()); | 1185 DCHECK(!isolate->has_pending_exception()); |
| 1087 DCHECK(function->shared()->is_compiled()); | 1186 DCHECK(function->shared()->is_compiled()); |
| 1088 DCHECK(function->is_compiled()); | 1187 DCHECK(function->is_compiled()); |
| 1089 return true; | 1188 return true; |
| 1090 } | 1189 } |
| 1091 | 1190 |
| 1191 bool Compiler::CompileBaseline(Handle<JSFunction> function) { | |
| 1192 Isolate* isolate = function->GetIsolate(); | |
| 1193 DCHECK(AllowCompilation::IsAllowed(isolate)); | |
| 1194 | |
| 1195 // Start a compilation. | |
| 1196 Handle<Code> code; | |
| 1197 if (!GetBaselineCode(function).ToHandle(&code)) { | |
| 1198 // Baseline generation failed, get unoptimized code. | |
| 1199 DCHECK(function->shared()->is_compiled()); | |
| 1200 code = handle(function->shared()->code()); | |
| 1201 isolate->clear_pending_exception(); | |
| 1202 } | |
| 1203 | |
| 1204 // Install code on closure. | |
| 1205 function->ReplaceCode(*code); | |
| 1206 | |
| 1207 // Check postconditions on success. | |
| 1208 DCHECK(!isolate->has_pending_exception()); | |
| 1209 DCHECK(function->shared()->is_compiled()); | |
| 1210 DCHECK(function->is_compiled()); | |
| 1211 return true; | |
| 1212 } | |
| 1213 | |
| 1092 bool Compiler::CompileOptimized(Handle<JSFunction> function, | 1214 bool Compiler::CompileOptimized(Handle<JSFunction> function, |
| 1093 ConcurrencyMode mode) { | 1215 ConcurrencyMode mode) { |
| 1094 if (function->IsOptimized()) return true; | 1216 if (function->IsOptimized()) return true; |
| 1095 Isolate* isolate = function->GetIsolate(); | 1217 Isolate* isolate = function->GetIsolate(); |
| 1096 DCHECK(AllowCompilation::IsAllowed(isolate)); | 1218 DCHECK(AllowCompilation::IsAllowed(isolate)); |
| 1097 | 1219 |
| 1098 // Start a compilation. | 1220 // Start a compilation. |
| 1099 Handle<Code> code; | 1221 Handle<Code> code; |
| 1100 if (!GetOptimizedCode(function, mode).ToHandle(&code)) { | 1222 if (!GetOptimizedCode(function, mode).ToHandle(&code)) { |
| 1101 // Optimization failed, get unoptimized code. | 1223 // Optimization failed, get unoptimized code. |
| (...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1677 MaybeHandle<Code> code; | 1799 MaybeHandle<Code> code; |
| 1678 if (cached.code != nullptr) code = handle(cached.code); | 1800 if (cached.code != nullptr) code = handle(cached.code); |
| 1679 Handle<Context> native_context(function->context()->native_context()); | 1801 Handle<Context> native_context(function->context()->native_context()); |
| 1680 SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code, | 1802 SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code, |
| 1681 literals, BailoutId::None()); | 1803 literals, BailoutId::None()); |
| 1682 } | 1804 } |
| 1683 } | 1805 } |
| 1684 | 1806 |
| 1685 } // namespace internal | 1807 } // namespace internal |
| 1686 } // namespace v8 | 1808 } // namespace v8 |
| OLD | NEW |