| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/compiler.h" | 5 #include "vm/compiler.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 | 8 |
| 9 #include "vm/ast_printer.h" | 9 #include "vm/ast_printer.h" |
| 10 #include "vm/block_scheduler.h" | 10 #include "vm/block_scheduler.h" |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 | 368 |
| 369 // Return false if bailed out. | 369 // Return false if bailed out. |
| 370 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, | 370 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, |
| 371 ParsedFunction* parsed_function, | 371 ParsedFunction* parsed_function, |
| 372 bool optimized, | 372 bool optimized, |
| 373 intptr_t osr_id) { | 373 intptr_t osr_id) { |
| 374 const Function& function = parsed_function->function(); | 374 const Function& function = parsed_function->function(); |
| 375 if (optimized && !function.IsOptimizable()) { | 375 if (optimized && !function.IsOptimizable()) { |
| 376 return false; | 376 return false; |
| 377 } | 377 } |
| 378 TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer); | 378 TimerScope timer(FLAG_compiler_stats, &CSTAT_TIMER(codegen_timer)); |
| 379 bool is_compiled = false; | 379 bool is_compiled = false; |
| 380 Thread* const thread = Thread::Current(); | 380 Thread* const thread = Thread::Current(); |
| 381 Zone* const zone = thread->zone(); | 381 Zone* const zone = thread->zone(); |
| 382 Isolate* const isolate = thread->isolate(); | 382 Isolate* const isolate = thread->isolate(); |
| 383 HANDLESCOPE(isolate); | 383 HANDLESCOPE(isolate); |
| 384 | 384 |
| 385 // We may reattempt compilation if the function needs to be assembled using | 385 // We may reattempt compilation if the function needs to be assembled using |
| 386 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 386 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
| 387 // done is set to false, and use_far_branches is set to true if there is a | 387 // done is set to false, and use_far_branches is set to true if there is a |
| 388 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 388 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
| (...skipping 10 matching lines...) Expand all Loading... |
| 399 FlowGraph* flow_graph = NULL; | 399 FlowGraph* flow_graph = NULL; |
| 400 | 400 |
| 401 // Class hierarchy analysis is registered with the isolate in the | 401 // Class hierarchy analysis is registered with the isolate in the |
| 402 // constructor and unregisters itself upon destruction. | 402 // constructor and unregisters itself upon destruction. |
| 403 CHA cha(thread); | 403 CHA cha(thread); |
| 404 | 404 |
| 405 // TimerScope needs an isolate to be properly terminated in case of a | 405 // TimerScope needs an isolate to be properly terminated in case of a |
| 406 // LongJump. | 406 // LongJump. |
| 407 { | 407 { |
| 408 TimerScope timer(FLAG_compiler_stats, | 408 TimerScope timer(FLAG_compiler_stats, |
| 409 &CompilerStats::graphbuilder_timer, | 409 &CSTAT_TIMER(graphbuilder_timer), |
| 410 isolate); | 410 isolate); |
| 411 ZoneGrowableArray<const ICData*>* ic_data_array = | 411 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 412 new(zone) ZoneGrowableArray<const ICData*>(); | 412 new(zone) ZoneGrowableArray<const ICData*>(); |
| 413 if (optimized) { | 413 if (optimized) { |
| 414 ASSERT(function.HasCode()); | 414 ASSERT(function.HasCode()); |
| 415 // Extract type feedback before the graph is built, as the graph | 415 // Extract type feedback before the graph is built, as the graph |
| 416 // builder uses it to attach it to nodes. | 416 // builder uses it to attach it to nodes. |
| 417 ASSERT(function.deoptimization_counter() < | 417 ASSERT(function.deoptimization_counter() < |
| 418 FLAG_deoptimization_counter_threshold); | 418 FLAG_deoptimization_counter_threshold); |
| 419 function.RestoreICDataMap(ic_data_array); | 419 function.RestoreICDataMap(ic_data_array); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 448 | 448 |
| 449 BlockScheduler block_scheduler(flow_graph); | 449 BlockScheduler block_scheduler(flow_graph); |
| 450 const bool reorder_blocks = | 450 const bool reorder_blocks = |
| 451 FlowGraph::ShouldReorderBlocks(function, optimized); | 451 FlowGraph::ShouldReorderBlocks(function, optimized); |
| 452 if (reorder_blocks) { | 452 if (reorder_blocks) { |
| 453 block_scheduler.AssignEdgeWeights(); | 453 block_scheduler.AssignEdgeWeights(); |
| 454 } | 454 } |
| 455 | 455 |
| 456 if (optimized) { | 456 if (optimized) { |
| 457 TimerScope timer(FLAG_compiler_stats, | 457 TimerScope timer(FLAG_compiler_stats, |
| 458 &CompilerStats::ssa_timer, | 458 &CSTAT_TIMER(ssa_timer), |
| 459 isolate); | 459 isolate); |
| 460 // Transform to SSA (virtual register 0 and no inlining arguments). | 460 // Transform to SSA (virtual register 0 and no inlining arguments). |
| 461 flow_graph->ComputeSSA(0, NULL); | 461 flow_graph->ComputeSSA(0, NULL); |
| 462 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 462 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 463 if (print_flow_graph) { | 463 if (print_flow_graph) { |
| 464 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); | 464 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); |
| 465 } | 465 } |
| 466 } | 466 } |
| 467 | 467 |
| 468 // Maps inline_id_to_function[inline_id] -> function. Top scope | 468 // Maps inline_id_to_function[inline_id] -> function. Top scope |
| 469 // function has inline_id 0. The map is populated by the inliner. | 469 // function has inline_id 0. The map is populated by the inliner. |
| 470 GrowableArray<const Function*> inline_id_to_function; | 470 GrowableArray<const Function*> inline_id_to_function; |
| 471 // For a given inlining-id(index) specifies the caller's inlining-id. | 471 // For a given inlining-id(index) specifies the caller's inlining-id. |
| 472 GrowableArray<intptr_t> caller_inline_id; | 472 GrowableArray<intptr_t> caller_inline_id; |
| 473 // Collect all instance fields that are loaded in the graph and | 473 // Collect all instance fields that are loaded in the graph and |
| 474 // have non-generic type feedback attached to them that can | 474 // have non-generic type feedback attached to them that can |
| 475 // potentially affect optimizations. | 475 // potentially affect optimizations. |
| 476 if (optimized) { | 476 if (optimized) { |
| 477 inline_id_to_function.Add(&function); | 477 inline_id_to_function.Add(&function); |
| 478 // Top scope function has no caller (-1). | 478 // Top scope function has no caller (-1). |
| 479 caller_inline_id.Add(-1); | 479 caller_inline_id.Add(-1); |
| 480 TimerScope timer(FLAG_compiler_stats, | 480 TimerScope timer(FLAG_compiler_stats, |
| 481 &CompilerStats::graphoptimizer_timer, | 481 &CSTAT_TIMER(graphoptimizer_timer), |
| 482 isolate); | 482 isolate); |
| 483 | 483 |
| 484 FlowGraphOptimizer optimizer(flow_graph); | 484 FlowGraphOptimizer optimizer(flow_graph); |
| 485 optimizer.ApplyICData(); | 485 optimizer.ApplyICData(); |
| 486 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 486 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 487 | 487 |
| 488 // Optimize (a << b) & c patterns, merge operations. | 488 // Optimize (a << b) & c patterns, merge operations. |
| 489 // Run early in order to have more opportunity to optimize left shifts. | 489 // Run early in order to have more opportunity to optimize left shifts. |
| 490 optimizer.TryOptimizePatterns(); | 490 optimizer.TryOptimizePatterns(); |
| 491 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 491 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 492 | 492 |
| 493 FlowGraphInliner::SetInliningId(flow_graph, 0); | 493 FlowGraphInliner::SetInliningId(flow_graph, 0); |
| 494 | 494 |
| 495 // Inlining (mutates the flow graph) | 495 // Inlining (mutates the flow graph) |
| 496 if (FLAG_use_inlining) { | 496 if (FLAG_use_inlining) { |
| 497 TimerScope timer(FLAG_compiler_stats, | 497 TimerScope timer(FLAG_compiler_stats, |
| 498 &CompilerStats::graphinliner_timer); | 498 &CSTAT_TIMER(graphinliner_timer)); |
| 499 // Propagate types to create more inlining opportunities. | 499 // Propagate types to create more inlining opportunities. |
| 500 FlowGraphTypePropagator::Propagate(flow_graph); | 500 FlowGraphTypePropagator::Propagate(flow_graph); |
| 501 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 501 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 502 | 502 |
| 503 // Use propagated class-ids to create more inlining opportunities. | 503 // Use propagated class-ids to create more inlining opportunities. |
| 504 optimizer.ApplyClassIds(); | 504 optimizer.ApplyClassIds(); |
| 505 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 505 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 506 | 506 |
| 507 FlowGraphInliner inliner(flow_graph, | 507 FlowGraphInliner inliner(flow_graph, |
| 508 &inline_id_to_function, | 508 &inline_id_to_function, |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 } | 703 } |
| 704 | 704 |
| 705 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); | 705 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); |
| 706 Assembler assembler(use_far_branches); | 706 Assembler assembler(use_far_branches); |
| 707 FlowGraphCompiler graph_compiler(&assembler, flow_graph, | 707 FlowGraphCompiler graph_compiler(&assembler, flow_graph, |
| 708 *parsed_function, optimized, | 708 *parsed_function, optimized, |
| 709 inline_id_to_function, | 709 inline_id_to_function, |
| 710 caller_inline_id); | 710 caller_inline_id); |
| 711 { | 711 { |
| 712 TimerScope timer(FLAG_compiler_stats, | 712 TimerScope timer(FLAG_compiler_stats, |
| 713 &CompilerStats::graphcompiler_timer, | 713 &CSTAT_TIMER(graphcompiler_timer), |
| 714 isolate); | 714 isolate); |
| 715 graph_compiler.CompileGraph(); | 715 graph_compiler.CompileGraph(); |
| 716 pipeline->FinalizeCompilation(); | 716 pipeline->FinalizeCompilation(); |
| 717 } | 717 } |
| 718 { | 718 { |
| 719 TimerScope timer(FLAG_compiler_stats, | 719 TimerScope timer(FLAG_compiler_stats, |
| 720 &CompilerStats::codefinalizer_timer, | 720 &CSTAT_TIMER(codefinalizer_timer), |
| 721 isolate); | 721 isolate); |
| 722 // CreateDeoptInfo uses the object pool and needs to be done before | 722 // CreateDeoptInfo uses the object pool and needs to be done before |
| 723 // FinalizeCode. | 723 // FinalizeCode. |
| 724 const Array& deopt_info_array = Array::Handle( | 724 const Array& deopt_info_array = |
| 725 graph_compiler.CreateDeoptInfo(&assembler)); | 725 Array::Handle(isolate, graph_compiler.CreateDeoptInfo(&assembler)); |
| 726 INC_STAT(isolate, total_code_size, |
| 727 deopt_info_array.Length() * sizeof(uword)); |
| 726 const Code& code = Code::Handle( | 728 const Code& code = Code::Handle( |
| 727 Code::FinalizeCode(function, &assembler, optimized)); | 729 Code::FinalizeCode(function, &assembler, optimized)); |
| 728 code.set_is_optimized(optimized); | 730 code.set_is_optimized(optimized); |
| 729 code.set_inlined_intervals(graph_compiler.inlined_code_intervals()); | 731 |
| 730 code.set_inlined_id_to_function( | 732 const Array& intervals = graph_compiler.inlined_code_intervals(); |
| 731 Array::Handle(graph_compiler.InliningIdToFunction())); | 733 INC_STAT(isolate, total_code_size, |
| 734 intervals.Length() * sizeof(uword)); |
| 735 code.set_inlined_intervals(intervals); |
| 736 |
| 737 const Array& inlined_id_array = |
| 738 Array::Handle(isolate, graph_compiler.InliningIdToFunction()); |
| 739 INC_STAT(isolate, total_code_size, |
| 740 inlined_id_array.Length() * sizeof(uword)); |
| 741 code.set_inlined_id_to_function(inlined_id_array); |
| 742 |
| 732 graph_compiler.FinalizePcDescriptors(code); | 743 graph_compiler.FinalizePcDescriptors(code); |
| 733 code.set_deopt_info_array(deopt_info_array); | 744 code.set_deopt_info_array(deopt_info_array); |
| 745 |
| 734 graph_compiler.FinalizeStackmaps(code); | 746 graph_compiler.FinalizeStackmaps(code); |
| 735 graph_compiler.FinalizeVarDescriptors(code); | 747 graph_compiler.FinalizeVarDescriptors(code); |
| 736 graph_compiler.FinalizeExceptionHandlers(code); | 748 graph_compiler.FinalizeExceptionHandlers(code); |
| 737 graph_compiler.FinalizeStaticCallTargetsTable(code); | 749 graph_compiler.FinalizeStaticCallTargetsTable(code); |
| 738 | 750 |
| 739 if (optimized) { | 751 if (optimized) { |
| 740 if (osr_id == Isolate::kNoDeoptId) { | 752 if (osr_id == Isolate::kNoDeoptId) { |
| 741 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); | 753 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); |
| 742 if (FLAG_trace_compiler || FLAG_trace_patching) { | 754 if (FLAG_trace_compiler || FLAG_trace_patching) { |
| 743 if (FLAG_trace_compiler) { | 755 if (FLAG_trace_compiler) { |
| (...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1305 const Object& result = | 1317 const Object& result = |
| 1306 PassiveObject::Handle(isolate->object_store()->sticky_error()); | 1318 PassiveObject::Handle(isolate->object_store()->sticky_error()); |
| 1307 isolate->object_store()->clear_sticky_error(); | 1319 isolate->object_store()->clear_sticky_error(); |
| 1308 return result.raw(); | 1320 return result.raw(); |
| 1309 } | 1321 } |
| 1310 UNREACHABLE(); | 1322 UNREACHABLE(); |
| 1311 return Object::null(); | 1323 return Object::null(); |
| 1312 } | 1324 } |
| 1313 | 1325 |
| 1314 } // namespace dart | 1326 } // namespace dart |
| OLD | NEW |