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 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "src/asmjs/asm-js.h" | 10 #include "src/asmjs/asm-js.h" |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 } | 298 } |
| 299 | 299 |
| 300 // It's very important that recompiles do not alter the structure of the type | 300 // It's very important that recompiles do not alter the structure of the type |
| 301 // feedback vector. Verify that the structure fits the function literal. | 301 // feedback vector. Verify that the structure fits the function literal. |
| 302 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom( | 302 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom( |
| 303 info->literal()->feedback_vector_spec())); | 303 info->literal()->feedback_vector_spec())); |
| 304 } | 304 } |
| 305 | 305 |
| 306 bool UseTurboFan(Handle<SharedFunctionInfo> shared) { | 306 bool UseTurboFan(Handle<SharedFunctionInfo> shared) { |
| 307 bool optimization_disabled = shared->optimization_disabled(); | 307 bool optimization_disabled = shared->optimization_disabled(); |
| 308 bool dont_crankshaft = shared->dont_crankshaft(); | 308 bool must_use_ignition_turbo = shared->must_use_ignition_turbo(); |
| 309 | 309 |
| 310 // Check the enabling conditions for Turbofan. | 310 // Check the enabling conditions for Turbofan. |
| 311 // 1. "use asm" code. | 311 // 1. "use asm" code. |
| 312 bool is_turbofanable_asm = | 312 bool is_turbofanable_asm = |
| 313 FLAG_turbo_asm && shared->asm_function() && !optimization_disabled; | 313 FLAG_turbo_asm && shared->asm_function() && !optimization_disabled; |
| 314 | 314 |
| 315 // 2. Fallback for features unsupported by Crankshaft. | 315 // 2. Fallback for features unsupported by Crankshaft. |
| 316 bool is_unsupported_by_crankshaft_but_turbofanable = | 316 bool is_unsupported_by_crankshaft_but_turbofanable = |
| 317 dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 && | 317 must_use_ignition_turbo && strcmp(FLAG_turbo_filter, "~~") == 0 && |
| 318 !optimization_disabled; | 318 !optimization_disabled; |
| 319 | 319 |
| 320 // 3. Explicitly enabled by the command-line filter. | 320 // 3. Explicitly enabled by the command-line filter. |
| 321 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); | 321 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); |
| 322 | 322 |
| 323 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || | 323 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || |
| 324 passes_turbo_filter; | 324 passes_turbo_filter; |
| 325 } | 325 } |
| 326 | 326 |
| 327 bool ShouldUseIgnition(CompilationInfo* info) { | 327 bool ShouldUseIgnition(CompilationInfo* info) { |
| 328 DCHECK(info->has_shared_info()); | 328 DCHECK(info->has_shared_info()); |
| 329 Handle<SharedFunctionInfo> shared = info->shared_info(); | |
| 330 | |
| 331 // Code which can't be supported by the old pipeline should use Ignition. | |
| 332 if (shared->must_use_ignition_turbo()) return true; | |
| 329 | 333 |
| 330 // Resumable functions are not supported by {FullCodeGenerator}, suspended | 334 // Resumable functions are not supported by {FullCodeGenerator}, suspended |
| 331 // activations stored as {JSGeneratorObject} on the heap always assume the | 335 // activations stored as {JSGeneratorObject} on the heap always assume the |
| 332 // underlying code to be based on the bytecode array. | 336 // underlying code to be based on the bytecode array. |
| 333 // TODO(mstarzinger): Once we want to deprecate even more support from the | 337 DCHECK(!IsResumableFunction(shared->kind())); |
| 334 // {FullCodeGenerator}, we will compute an appropriate bit in {AstNumbering} | |
| 335 // and turn this predicate into a DCHECK instead. | |
| 336 if (IsResumableFunction(info->shared_info()->kind())) { | |
| 337 return true; | |
| 338 } | |
| 339 | 338 |
| 340 // Skip Ignition for asm.js functions. | 339 // Skip Ignition for asm.js functions. |
| 341 if (info->shared_info()->asm_function()) { | 340 if (shared->asm_function()) return false; |
| 341 | |
| 342 // Skip Ignition for asm wasm code. | |
| 343 if (FLAG_validate_asm && shared->HasAsmWasmData()) { | |
| 342 return false; | 344 return false; |
| 343 } | 345 } |
| 344 | 346 |
| 345 // When requesting debug code as a replacement for existing code, we provide | 347 // When requesting debug code as a replacement for existing code, we provide |
| 346 // the same kind as the existing code (to prevent implicit tier-change). | 348 // the same kind as the existing code (to prevent implicit tier-change). |
| 347 if (info->is_debug() && info->shared_info()->is_compiled()) { | 349 if (info->is_debug() && shared->is_compiled()) { |
| 348 return !info->shared_info()->HasBaselineCode(); | 350 return !shared->HasBaselineCode(); |
| 349 } | 351 } |
| 350 | 352 |
| 351 // Code destined for TurboFan should be compiled with Ignition first. | 353 // Code destined for TurboFan should be compiled with Ignition first. |
| 352 if (UseTurboFan(info->shared_info())) return true; | 354 if (UseTurboFan(shared)) return true; |
| 353 | 355 |
| 354 // Only use Ignition for any other function if FLAG_ignition is true. | 356 // Only use Ignition for any other function if FLAG_ignition is true. |
| 355 if (!FLAG_ignition) return false; | 357 if (!FLAG_ignition) return false; |
| 356 | 358 |
| 357 // Checks whether top level functions should be passed by the filter. | 359 // Checks whether top level functions should be passed by the filter. |
| 358 if (info->shared_info()->is_toplevel()) { | 360 if (shared->is_toplevel()) { |
| 359 Vector<const char> filter = CStrVector(FLAG_ignition_filter); | 361 Vector<const char> filter = CStrVector(FLAG_ignition_filter); |
| 360 return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*'); | 362 return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*'); |
| 361 } | 363 } |
| 362 | 364 |
| 363 // Finally respect the filter. | 365 // Finally respect the filter. |
| 364 return info->shared_info()->PassesFilter(FLAG_ignition_filter); | 366 return shared->PassesFilter(FLAG_ignition_filter); |
| 365 } | 367 } |
| 366 | 368 |
| 367 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { | 369 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { |
| 368 // Function should have been parsed and analyzed before creating a compilation | 370 // Function should have been parsed and analyzed before creating a compilation |
| 369 // job. | 371 // job. |
| 370 DCHECK_NOT_NULL(info->literal()); | 372 DCHECK_NOT_NULL(info->literal()); |
| 371 DCHECK_NOT_NULL(info->scope()); | 373 DCHECK_NOT_NULL(info->scope()); |
| 372 | 374 |
| 373 EnsureFeedbackMetadata(info); | 375 EnsureFeedbackMetadata(info); |
| 374 if (ShouldUseIgnition(info)) { | 376 if (ShouldUseIgnition(info)) { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 parse_info->literal())) { | 522 parse_info->literal())) { |
| 521 return false; | 523 return false; |
| 522 } | 524 } |
| 523 Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); | 525 Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); |
| 524 if (!shared_info.is_null()) { | 526 if (!shared_info.is_null()) { |
| 525 FunctionLiteral* lit = parse_info->literal(); | 527 FunctionLiteral* lit = parse_info->literal(); |
| 526 shared_info->set_ast_node_count(lit->ast_node_count()); | 528 shared_info->set_ast_node_count(lit->ast_node_count()); |
| 527 if (lit->dont_optimize_reason() != kNoReason) { | 529 if (lit->dont_optimize_reason() != kNoReason) { |
| 528 shared_info->DisableOptimization(lit->dont_optimize_reason()); | 530 shared_info->DisableOptimization(lit->dont_optimize_reason()); |
| 529 } | 531 } |
| 530 if (lit->flags() & AstProperties::kDontCrankshaft) { | 532 if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) { |
| 531 shared_info->set_dont_crankshaft(true); | 533 shared_info->set_must_use_ignition_turbo(true); |
| 532 } | 534 } |
| 533 } | 535 } |
| 534 return true; | 536 return true; |
| 535 } | 537 } |
| 536 | 538 |
| 537 bool GetOptimizedCodeNow(CompilationJob* job) { | 539 bool GetOptimizedCodeNow(CompilationJob* job) { |
| 538 CompilationInfo* info = job->info(); | 540 CompilationInfo* info = job->info(); |
| 539 Isolate* isolate = info->isolate(); | 541 Isolate* isolate = info->isolate(); |
| 540 | 542 |
| 541 // Parsing is not required when optimizing from existing bytecode. | 543 // Parsing is not required when optimizing from existing bytecode. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 643 function->ShortPrint(); | 645 function->ShortPrint(); |
| 644 if (!osr_ast_id.IsNone()) { | 646 if (!osr_ast_id.IsNone()) { |
| 645 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); | 647 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); |
| 646 } | 648 } |
| 647 PrintF("]\n"); | 649 PrintF("]\n"); |
| 648 } | 650 } |
| 649 return cached_code; | 651 return cached_code; |
| 650 } | 652 } |
| 651 | 653 |
| 652 // Reset profiler ticks, function is no longer considered hot. | 654 // Reset profiler ticks, function is no longer considered hot. |
| 655 DCHECK(shared->is_compiled()); | |
| 653 if (shared->HasBaselineCode()) { | 656 if (shared->HasBaselineCode()) { |
| 654 shared->code()->set_profiler_ticks(0); | 657 shared->code()->set_profiler_ticks(0); |
| 655 } else if (shared->HasBytecodeArray()) { | 658 } else if (shared->HasBytecodeArray()) { |
| 656 shared->set_profiler_ticks(0); | 659 shared->set_profiler_ticks(0); |
| 657 } | 660 } |
| 658 | 661 |
| 659 VMState<COMPILER> state(isolate); | 662 VMState<COMPILER> state(isolate); |
| 660 DCHECK(!isolate->has_pending_exception()); | 663 DCHECK(!isolate->has_pending_exception()); |
| 661 PostponeInterruptsScope postpone(isolate); | 664 PostponeInterruptsScope postpone(isolate); |
| 662 bool use_turbofan = UseTurboFan(shared) || ignition_osr; | 665 bool use_turbofan = UseTurboFan(shared) || ignition_osr; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 682 return MaybeHandle<Code>(); | 685 return MaybeHandle<Code>(); |
| 683 } | 686 } |
| 684 | 687 |
| 685 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate); | 688 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate); |
| 686 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode); | 689 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode); |
| 687 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); | 690 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); |
| 688 | 691 |
| 689 // TurboFan can optimize directly from existing bytecode. | 692 // TurboFan can optimize directly from existing bytecode. |
| 690 if (use_turbofan && ShouldUseIgnition(info)) { | 693 if (use_turbofan && ShouldUseIgnition(info)) { |
| 691 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>(); | 694 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>(); |
| 692 if (!Compiler::EnsureBytecode(info)) { | 695 DCHECK(shared->HasBytecodeArray()); |
| 693 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); | |
| 694 return MaybeHandle<Code>(); | |
| 695 } | |
| 696 info->MarkAsOptimizeFromBytecode(); | 696 info->MarkAsOptimizeFromBytecode(); |
| 697 } | 697 } |
| 698 | 698 |
| 699 // Verify that OSR compilations are delegated to the correct graph builder. | 699 // Verify that OSR compilations are delegated to the correct graph builder. |
| 700 // Depending on the underlying frame the semantics of the {BailoutId} differ | 700 // Depending on the underlying frame the semantics of the {BailoutId} differ |
| 701 // and the various graph builders hard-code a certain semantic: | 701 // and the various graph builders hard-code a certain semantic: |
| 702 // - Interpreter : The BailoutId represents a bytecode offset. | 702 // - Interpreter : The BailoutId represents a bytecode offset. |
| 703 // - FullCodegen : The BailoutId represents the id of an AST node. | 703 // - FullCodegen : The BailoutId represents the id of an AST node. |
| 704 DCHECK_IMPLIES(info->is_osr() && ignition_osr, | 704 DCHECK_IMPLIES(info->is_osr() && ignition_osr, |
| 705 info->is_optimizing_from_bytecode()); | 705 info->is_optimizing_from_bytecode()); |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1187 | 1187 |
| 1188 // Restore the original function info list in order to remain side-effect | 1188 // Restore the original function info list in order to remain side-effect |
| 1189 // free as much as possible, since some code expects the old shared function | 1189 // free as much as possible, since some code expects the old shared function |
| 1190 // infos to stick around. | 1190 // infos to stick around. |
| 1191 script->set_shared_function_infos(*old_function_infos); | 1191 script->set_shared_function_infos(*old_function_infos); |
| 1192 | 1192 |
| 1193 return infos; | 1193 return infos; |
| 1194 } | 1194 } |
| 1195 | 1195 |
| 1196 bool Compiler::EnsureBytecode(CompilationInfo* info) { | 1196 bool Compiler::EnsureBytecode(CompilationInfo* info) { |
| 1197 if (!ShouldUseIgnition(info)) return false; | 1197 if (!info->shared_info()->is_compiled()) { |
| 1198 if (!info->shared_info()->HasBytecodeArray()) { | |
| 1199 Handle<Code> original_code(info->shared_info()->code()); | |
| 1200 if (GetUnoptimizedCode(info).is_null()) return false; | 1198 if (GetUnoptimizedCode(info).is_null()) return false; |
| 1201 if (info->shared_info()->HasAsmWasmData()) return false; | 1199 if (info->shared_info()->HasAsmWasmData()) return false; |
| 1202 DCHECK(info->shared_info()->is_compiled()); | 1200 DCHECK(info->shared_info()->is_compiled()); |
| 1203 if (original_code->kind() == Code::FUNCTION) { | |
| 1204 // Generating bytecode will install the {InterpreterEntryTrampoline} as | |
| 1205 // shared code on the function. To avoid an implicit tier down we restore | |
| 1206 // original baseline code in case it existed beforehand. | |
| 1207 info->shared_info()->ReplaceCode(*original_code); | |
| 1208 } | |
| 1209 } | 1201 } |
| 1210 DCHECK(info->shared_info()->HasBytecodeArray()); | 1202 DCHECK_EQ(ShouldUseIgnition(info), info->shared_info()->HasBytecodeArray()); |
| 1211 return true; | 1203 return info->shared_info()->HasBytecodeArray(); |
| 1212 } | 1204 } |
| 1213 | 1205 |
| 1214 // TODO(turbofan): In the future, unoptimized code with deopt support could | 1206 // TODO(turbofan): In the future, unoptimized code with deopt support could |
| 1215 // be generated lazily once deopt is triggered. | 1207 // be generated lazily once deopt is triggered. |
| 1216 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { | 1208 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { |
| 1217 DCHECK_NOT_NULL(info->literal()); | 1209 DCHECK_NOT_NULL(info->literal()); |
| 1218 DCHECK_NOT_NULL(info->scope()); | 1210 DCHECK_NOT_NULL(info->scope()); |
| 1219 Handle<SharedFunctionInfo> shared = info->shared_info(); | 1211 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1220 if (!shared->has_deoptimization_support()) { | 1212 if (!shared->has_deoptimization_support()) { |
| 1221 Zone zone(info->isolate()->allocator(), ZONE_NAME); | 1213 Zone zone(info->isolate()->allocator(), ZONE_NAME); |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1707 return true; | 1699 return true; |
| 1708 } | 1700 } |
| 1709 return false; | 1701 return false; |
| 1710 } | 1702 } |
| 1711 } | 1703 } |
| 1712 | 1704 |
| 1713 void Compiler::PostInstantiation(Handle<JSFunction> function, | 1705 void Compiler::PostInstantiation(Handle<JSFunction> function, |
| 1714 PretenureFlag pretenure) { | 1706 PretenureFlag pretenure) { |
| 1715 Handle<SharedFunctionInfo> shared(function->shared()); | 1707 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1716 | 1708 |
| 1717 if (FLAG_always_opt && shared->allows_lazy_compilation()) { | 1709 if (FLAG_always_opt && shared->allows_lazy_compilation() && |
| 1710 function->shared()->is_compiled()) { | |
|
rmcilroy
2016/11/22 14:03:44
With this change we only mark for optimization if
Michael Starzinger
2016/11/22 14:53:50
Acknowledged. I thought about this for a little bi
rmcilroy
2016/11/22 17:24:02
Acknowledged.
| |
| 1718 function->MarkForOptimization(); | 1711 function->MarkForOptimization(); |
| 1719 } | 1712 } |
| 1720 | 1713 |
| 1721 CodeAndLiterals cached = shared->SearchOptimizedCodeMap( | 1714 CodeAndLiterals cached = shared->SearchOptimizedCodeMap( |
| 1722 function->context()->native_context(), BailoutId::None()); | 1715 function->context()->native_context(), BailoutId::None()); |
| 1723 if (cached.code != nullptr) { | 1716 if (cached.code != nullptr) { |
| 1724 // Caching of optimized code enabled and optimized code found. | 1717 // Caching of optimized code enabled and optimized code found. |
| 1725 DCHECK(!cached.code->marked_for_deoptimization()); | 1718 DCHECK(!cached.code->marked_for_deoptimization()); |
| 1726 DCHECK(function->shared()->is_compiled()); | 1719 DCHECK(function->shared()->is_compiled()); |
| 1727 function->ReplaceCode(cached.code); | 1720 function->ReplaceCode(cached.code); |
| 1728 } | 1721 } |
| 1729 | 1722 |
| 1730 if (cached.literals != nullptr) { | 1723 if (cached.literals != nullptr) { |
| 1731 DCHECK(shared->is_compiled()); | 1724 DCHECK(shared->is_compiled()); |
| 1732 function->set_literals(cached.literals); | 1725 function->set_literals(cached.literals); |
| 1733 } else if (shared->is_compiled()) { | 1726 } else if (shared->is_compiled()) { |
| 1734 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. | 1727 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. |
| 1735 JSFunction::EnsureLiterals(function); | 1728 JSFunction::EnsureLiterals(function); |
| 1736 } | 1729 } |
| 1737 } | 1730 } |
| 1738 | 1731 |
| 1739 } // namespace internal | 1732 } // namespace internal |
| 1740 } // namespace v8 | 1733 } // namespace v8 |
| OLD | NEW |