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

Side by Side Diff: runtime/vm/compiler.cc

Issue 1663163003: Initial split of precompilation code from compiler.cc (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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
OLDNEW
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 12 matching lines...) Expand all
23 #include "vm/flow_graph_compiler.h" 23 #include "vm/flow_graph_compiler.h"
24 #include "vm/flow_graph_inliner.h" 24 #include "vm/flow_graph_inliner.h"
25 #include "vm/flow_graph_optimizer.h" 25 #include "vm/flow_graph_optimizer.h"
26 #include "vm/flow_graph_type_propagator.h" 26 #include "vm/flow_graph_type_propagator.h"
27 #include "vm/il_printer.h" 27 #include "vm/il_printer.h"
28 #include "vm/longjump.h" 28 #include "vm/longjump.h"
29 #include "vm/object.h" 29 #include "vm/object.h"
30 #include "vm/object_store.h" 30 #include "vm/object_store.h"
31 #include "vm/os.h" 31 #include "vm/os.h"
32 #include "vm/parser.h" 32 #include "vm/parser.h"
33 #include "vm/precompiler.h"
33 #include "vm/regexp_parser.h" 34 #include "vm/regexp_parser.h"
34 #include "vm/regexp_assembler.h" 35 #include "vm/regexp_assembler.h"
35 #include "vm/scanner.h"
36 #include "vm/symbols.h" 36 #include "vm/symbols.h"
37 #include "vm/tags.h" 37 #include "vm/tags.h"
38 #include "vm/thread_registry.h" 38 #include "vm/thread_registry.h"
39 #include "vm/timer.h" 39 #include "vm/timer.h"
40 40
41 namespace dart { 41 namespace dart {
42 42
43 DEFINE_FLAG(bool, allocation_sinking, true, 43 DEFINE_FLAG(bool, allocation_sinking, true,
44 "Attempt to sink temporary allocations to side exits"); 44 "Attempt to sink temporary allocations to side exits");
45 DEFINE_FLAG(bool, common_subexpression_elimination, true, 45 DEFINE_FLAG(bool, common_subexpression_elimination, true,
(...skipping 13 matching lines...) Expand all
59 "Print the deopt-id to ICData map in optimizing compiler."); 59 "Print the deopt-id to ICData map in optimizing compiler.");
60 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis"); 60 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis");
61 DEFINE_FLAG(bool, reorder_basic_blocks, true, "Enable basic-block reordering."); 61 DEFINE_FLAG(bool, reorder_basic_blocks, true, "Enable basic-block reordering.");
62 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); 62 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations.");
63 DEFINE_FLAG(bool, trace_optimizing_compiler, false, 63 DEFINE_FLAG(bool, trace_optimizing_compiler, false,
64 "Trace only optimizing compiler operations."); 64 "Trace only optimizing compiler operations.");
65 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); 65 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler.");
66 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); 66 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining");
67 DEFINE_FLAG(bool, verify_compiler, false, 67 DEFINE_FLAG(bool, verify_compiler, false,
68 "Enable compiler verification assertions"); 68 "Enable compiler verification assertions");
69 DEFINE_FLAG(int, max_speculative_inlining_attempts, 1,
70 "Max number of attempts with speculative inlining (precompilation only)");
71 69
72 DECLARE_FLAG(bool, background_compilation); 70 DECLARE_FLAG(bool, background_compilation);
73 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); 71 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
74 DECLARE_FLAG(bool, load_deferred_eagerly); 72 DECLARE_FLAG(bool, load_deferred_eagerly);
75 DECLARE_FLAG(bool, trace_failed_optimization_attempts); 73 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
76 DECLARE_FLAG(bool, trace_inlining_intervals); 74 DECLARE_FLAG(bool, trace_inlining_intervals);
77 DECLARE_FLAG(bool, trace_irregexp); 75 DECLARE_FLAG(bool, trace_irregexp);
78 DECLARE_FLAG(bool, precompilation); 76 DECLARE_FLAG(bool, precompilation);
79 77
80 78
81 #ifndef DART_PRECOMPILED_RUNTIME 79 #ifndef DART_PRECOMPILED_RUNTIME
82 80
83 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove 81 void DartCompilationPipeline::ParseFunction(ParsedFunction* parsed_function) {
84 // separate helpers functions & `optimizing` args. 82 Parser::ParseFunction(parsed_function);
85 class CompilationPipeline : public ZoneAllocated { 83 parsed_function->AllocateVariables();
86 public: 84 }
87 static CompilationPipeline* New(Zone* zone, const Function& function);
88
89 virtual void ParseFunction(ParsedFunction* parsed_function) = 0;
90 virtual FlowGraph* BuildFlowGraph(
91 Zone* zone,
92 ParsedFunction* parsed_function,
93 const ZoneGrowableArray<const ICData*>& ic_data_array,
94 intptr_t osr_id) = 0;
95 virtual void FinalizeCompilation() = 0;
96 virtual ~CompilationPipeline() { }
97 };
98 85
99 86
100 class DartCompilationPipeline : public CompilationPipeline { 87 FlowGraph* DartCompilationPipeline::BuildFlowGraph(
101 public: 88 Zone* zone,
102 virtual void ParseFunction(ParsedFunction* parsed_function) { 89 ParsedFunction* parsed_function,
103 Parser::ParseFunction(parsed_function); 90 const ZoneGrowableArray<const ICData*>& ic_data_array,
104 parsed_function->AllocateVariables(); 91 intptr_t osr_id) {
105 } 92 // Build the flow graph.
93 FlowGraphBuilder builder(*parsed_function,
94 ic_data_array,
95 NULL, // NULL = not inlining.
96 osr_id);
106 97
107 virtual FlowGraph* BuildFlowGraph( 98 return builder.BuildGraph();
108 Zone* zone, 99 }
109 ParsedFunction* parsed_function,
110 const ZoneGrowableArray<const ICData*>& ic_data_array,
111 intptr_t osr_id) {
112 // Build the flow graph.
113 FlowGraphBuilder builder(*parsed_function,
114 ic_data_array,
115 NULL, // NULL = not inlining.
116 osr_id);
117
118 return builder.BuildGraph();
119 }
120
121 virtual void FinalizeCompilation() { }
122 };
123 100
124 101
125 class IrregexpCompilationPipeline : public CompilationPipeline { 102 void DartCompilationPipeline::FinalizeCompilation() { }
126 public:
127 IrregexpCompilationPipeline() : backtrack_goto_(NULL) { }
128 103
129 virtual void ParseFunction(ParsedFunction* parsed_function) {
130 RegExpParser::ParseFunction(parsed_function);
131 // Variables are allocated after compilation.
132 }
133 104
134 virtual FlowGraph* BuildFlowGraph( 105 void IrregexpCompilationPipeline::ParseFunction(
135 Zone* zone, 106 ParsedFunction* parsed_function) {
136 ParsedFunction* parsed_function, 107 RegExpParser::ParseFunction(parsed_function);
137 const ZoneGrowableArray<const ICData*>& ic_data_array, 108 // Variables are allocated after compilation.
138 intptr_t osr_id) { 109 }
139 // Compile to the dart IR.
140 RegExpEngine::CompilationResult result =
141 RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
142 parsed_function,
143 ic_data_array);
144 backtrack_goto_ = result.backtrack_goto;
145 110
146 // Allocate variables now that we know the number of locals. 111 FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph(
147 parsed_function->AllocateIrregexpVariables(result.num_stack_locals); 112 Zone* zone,
113 ParsedFunction* parsed_function,
114 const ZoneGrowableArray<const ICData*>& ic_data_array,
115 intptr_t osr_id) {
116 // Compile to the dart IR.
117 RegExpEngine::CompilationResult result =
118 RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
119 parsed_function,
120 ic_data_array);
121 backtrack_goto_ = result.backtrack_goto;
148 122
149 // Build the flow graph. 123 // Allocate variables now that we know the number of locals.
150 FlowGraphBuilder builder(*parsed_function, 124 parsed_function->AllocateIrregexpVariables(result.num_stack_locals);
151 ic_data_array,
152 NULL, // NULL = not inlining.
153 osr_id);
154 125
155 return new(zone) FlowGraph(*parsed_function, 126 // Build the flow graph.
156 result.graph_entry, 127 FlowGraphBuilder builder(*parsed_function,
157 result.num_blocks); 128 ic_data_array,
158 } 129 NULL, // NULL = not inlining.
130 osr_id);
159 131
160 virtual void FinalizeCompilation() { 132 return new(zone) FlowGraph(*parsed_function,
161 backtrack_goto_->ComputeOffsetTable(); 133 result.graph_entry,
162 } 134 result.num_blocks);
135 }
163 136
164 private: 137 void IrregexpCompilationPipeline::FinalizeCompilation() {
165 IndirectGotoInstr* backtrack_goto_; 138 backtrack_goto_->ComputeOffsetTable();
166 }; 139 }
167
168 140
169 CompilationPipeline* CompilationPipeline::New(Zone* zone, 141 CompilationPipeline* CompilationPipeline::New(Zone* zone,
170 const Function& function) { 142 const Function& function) {
171 if (function.IsIrregexpFunction()) { 143 if (function.IsIrregexpFunction()) {
172 return new(zone) IrregexpCompilationPipeline(); 144 return new(zone) IrregexpCompilationPipeline();
173 } else { 145 } else {
174 return new(zone) DartCompilationPipeline(); 146 return new(zone) DartCompilationPipeline();
175 } 147 }
176 } 148 }
177 149
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 const uint32_t prefix_invalidation_gen_at_start_; 413 const uint32_t prefix_invalidation_gen_at_start_;
442 414
443 DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper); 415 DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper);
444 }; 416 };
445 417
446 418
447 void CompileParsedFunctionHelper::FinalizeCompilation( 419 void CompileParsedFunctionHelper::FinalizeCompilation(
448 Assembler* assembler, 420 Assembler* assembler,
449 FlowGraphCompiler* graph_compiler, 421 FlowGraphCompiler* graph_compiler,
450 FlowGraph* flow_graph) { 422 FlowGraph* flow_graph) {
423 ASSERT(!FLAG_precompilation);
451 const Function& function = parsed_function()->function(); 424 const Function& function = parsed_function()->function();
452 Zone* const zone = thread()->zone(); 425 Zone* const zone = thread()->zone();
453 426
454 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer); 427 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer);
455 // CreateDeoptInfo uses the object pool and needs to be done before 428 // CreateDeoptInfo uses the object pool and needs to be done before
456 // FinalizeCode. 429 // FinalizeCode.
457 const Array& deopt_info_array = 430 const Array& deopt_info_array =
458 Array::Handle(zone, graph_compiler->CreateDeoptInfo(assembler)); 431 Array::Handle(zone, graph_compiler->CreateDeoptInfo(assembler));
459 INC_STAT(thread(), total_code_size, 432 INC_STAT(thread(), total_code_size,
460 deopt_info_array.Length() * sizeof(uword)); 433 deopt_info_array.Length() * sizeof(uword));
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 ASSERT(!is_osr); // OSR is compiled in background. 512 ASSERT(!is_osr); // OSR is compiled in background.
540 function.InstallOptimizedCode(code, is_osr); 513 function.InstallOptimizedCode(code, is_osr);
541 } 514 }
542 if (function.usage_counter() < 0) { 515 if (function.usage_counter() < 0) {
543 // Reset to 0 so that it can be recompiled if needed. 516 // Reset to 0 so that it can be recompiled if needed.
544 function.set_usage_counter(0); 517 function.set_usage_counter(0);
545 } 518 }
546 } 519 }
547 520
548 // Register code with the classes it depends on because of CHA and 521 // Register code with the classes it depends on because of CHA and
549 // fields it depends on because of store guards, unless we cannot 522 // fields it depends on because of store guards.
550 // deopt. 523 // Deoptimize field dependent code first, before registering
551 if (!FLAG_precompilation) { 524 // this yet uninstalled code as dependent on a field.
552 // Deoptimize field dependent code first, before registering 525 // TODO(srdjan): Debugging dart2js crashes;
553 // this yet uninstalled code as dependent on a field. 526 // FlowGraphOptimizer::VisitStoreInstanceField populates
554 // TODO(srdjan): Debugging dart2js crashes; 527 // deoptimize_dependent_code() list, currently disabled.
555 // FlowGraphOptimizer::VisitStoreInstanceField populates 528 for (intptr_t i = 0;
556 // deoptimize_dependent_code() list, currently disabled. 529 i < flow_graph->deoptimize_dependent_code().length();
557 for (intptr_t i = 0; 530 i++) {
558 i < flow_graph->deoptimize_dependent_code().length(); 531 const Field* field = flow_graph->deoptimize_dependent_code()[i];
559 i++) { 532 field->DeoptimizeDependentCode();
560 const Field* field = flow_graph->deoptimize_dependent_code()[i]; 533 }
561 field->DeoptimizeDependentCode(); 534 for (intptr_t i = 0;
562 } 535 i < thread()->cha()->leaf_classes().length();
563 for (intptr_t i = 0; 536 ++i) {
564 i < thread()->cha()->leaf_classes().length(); 537 thread()->cha()->leaf_classes()[i]->RegisterCHACode(code);
565 ++i) { 538 }
566 thread()->cha()->leaf_classes()[i]->RegisterCHACode(code); 539 for (intptr_t i = 0;
567 } 540 i < flow_graph->guarded_fields()->length();
568 for (intptr_t i = 0; 541 i++) {
569 i < flow_graph->guarded_fields()->length(); 542 const Field* field = (*flow_graph->guarded_fields())[i];
570 i++) { 543 field->RegisterDependentCode(code);
571 const Field* field = (*flow_graph->guarded_fields())[i];
572 field->RegisterDependentCode(code);
573 }
574 } 544 }
575 } else { // not optimized. 545 } else { // not optimized.
576 if (!FLAG_precompilation && 546 if (function.ic_data_array() == Array::null()) {
577 (function.ic_data_array() == Array::null())) {
578 function.SaveICDataMap( 547 function.SaveICDataMap(
579 graph_compiler->deopt_id_to_ic_data(), 548 graph_compiler->deopt_id_to_ic_data(),
580 Array::Handle(zone, graph_compiler->edge_counters_array())); 549 Array::Handle(zone, graph_compiler->edge_counters_array()));
581 } 550 }
582 function.set_unoptimized_code(code); 551 function.set_unoptimized_code(code);
583 function.AttachCode(code); 552 function.AttachCode(code);
584 } 553 }
585 if (parsed_function()->HasDeferredPrefixes()) { 554 if (parsed_function()->HasDeferredPrefixes()) {
586 ASSERT(!FLAG_load_deferred_eagerly); 555 ASSERT(!FLAG_load_deferred_eagerly);
587 ZoneGrowableArray<const LibraryPrefix*>* prefixes = 556 ZoneGrowableArray<const LibraryPrefix*>* prefixes =
588 parsed_function()->deferred_prefixes(); 557 parsed_function()->deferred_prefixes();
589 for (intptr_t i = 0; i < prefixes->length(); i++) { 558 for (intptr_t i = 0; i < prefixes->length(); i++) {
590 (*prefixes)[i]->RegisterDependentCode(code); 559 (*prefixes)[i]->RegisterDependentCode(code);
591 } 560 }
592 } 561 }
593 } 562 }
594 563
595 564
596 // Return false if bailed out. 565 // Return false if bailed out.
597 // If optimized_result_code is not NULL then it is caller's responsibility 566 // If optimized_result_code is not NULL then it is caller's responsibility
598 // to install code. 567 // to install code.
599 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { 568 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
569 ASSERT(!FLAG_precompilation);
600 const Function& function = parsed_function()->function(); 570 const Function& function = parsed_function()->function();
601 if (optimized() && !function.IsOptimizable()) { 571 if (optimized() && !function.IsOptimizable()) {
602 return false; 572 return false;
603 } 573 }
604 bool is_compiled = false; 574 bool is_compiled = false;
605 Zone* const zone = thread()->zone(); 575 Zone* const zone = thread()->zone();
606 TimelineStream* compiler_timeline = isolate()->GetCompilerStream(); 576 TimelineStream* compiler_timeline = isolate()->GetCompilerStream();
607 CSTAT_TIMER_SCOPE(thread(), codegen_timer); 577 CSTAT_TIMER_SCOPE(thread(), codegen_timer);
608 HANDLESCOPE(thread()); 578 HANDLESCOPE(thread());
609 579
610 // We may reattempt compilation if the function needs to be assembled using 580 // We may reattempt compilation if the function needs to be assembled using
611 // far branches on ARM and MIPS. In the else branch of the setjmp call, 581 // far branches on ARM and MIPS. In the else branch of the setjmp call,
612 // done is set to false, and use_far_branches is set to true if there is a 582 // done is set to false, and use_far_branches is set to true if there is a
613 // longjmp from the ARM or MIPS assemblers. In all other paths through this 583 // longjmp from the ARM or MIPS assemblers. In all other paths through this
614 // while loop, done is set to true. use_far_branches is always false on ia32 584 // while loop, done is set to true. use_far_branches is always false on ia32
615 // and x64. 585 // and x64.
616 bool done = false; 586 bool done = false;
617 // volatile because the variable may be clobbered by a longjmp. 587 // volatile because the variable may be clobbered by a longjmp.
618 volatile bool use_far_branches = false; 588 volatile bool use_far_branches = false;
619 volatile bool use_speculative_inlining = 589 volatile bool use_speculative_inlining = false;
rmacnak 2016/02/04 00:36:39 volatile -> const
Florian Schneider 2016/02/05 01:55:52 Done.
620 FLAG_max_speculative_inlining_attempts > 0;
621 GrowableArray<intptr_t> inlining_black_list;
622 590
623 while (!done) { 591 while (!done) {
624 const intptr_t prev_deopt_id = thread()->deopt_id(); 592 const intptr_t prev_deopt_id = thread()->deopt_id();
625 thread()->set_deopt_id(0); 593 thread()->set_deopt_id(0);
626 LongJumpScope jump; 594 LongJumpScope jump;
627 const intptr_t val = setjmp(*jump.Set()); 595 const intptr_t val = setjmp(*jump.Set());
628 if (val == 0) { 596 if (val == 0) {
629 FlowGraph* flow_graph = NULL; 597 FlowGraph* flow_graph = NULL;
630 598
631 // Class hierarchy analysis is registered with the isolate in the 599 // Class hierarchy analysis is registered with the isolate in the
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 TimelineDurationScope tds(thread(), 684 TimelineDurationScope tds(thread(),
717 compiler_timeline, 685 compiler_timeline,
718 "OptimizationPasses"); 686 "OptimizationPasses");
719 inline_id_to_function.Add(&function); 687 inline_id_to_function.Add(&function);
720 // Top scope function has no caller (-1). 688 // Top scope function has no caller (-1).
721 caller_inline_id.Add(-1); 689 caller_inline_id.Add(-1);
722 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); 690 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
723 691
724 FlowGraphOptimizer optimizer(flow_graph, 692 FlowGraphOptimizer optimizer(flow_graph,
725 use_speculative_inlining, 693 use_speculative_inlining,
726 &inlining_black_list); 694 NULL);
727 if (FLAG_precompilation) {
728 optimizer.PopulateWithICData();
729
730 optimizer.ApplyClassIds();
731 DEBUG_ASSERT(flow_graph->VerifyUseLists());
732
733 FlowGraphTypePropagator::Propagate(flow_graph);
734 DEBUG_ASSERT(flow_graph->VerifyUseLists());
735 }
736 optimizer.ApplyICData(); 695 optimizer.ApplyICData();
737 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 696 DEBUG_ASSERT(flow_graph->VerifyUseLists());
738 697
739 // Optimize (a << b) & c patterns, merge operations. 698 // Optimize (a << b) & c patterns, merge operations.
740 // Run early in order to have more opportunity to optimize left shifts. 699 // Run early in order to have more opportunity to optimize left shifts.
741 optimizer.TryOptimizePatterns(); 700 optimizer.TryOptimizePatterns();
742 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 701 DEBUG_ASSERT(flow_graph->VerifyUseLists());
743 702
744 FlowGraphInliner::SetInliningId(flow_graph, 0); 703 FlowGraphInliner::SetInliningId(flow_graph, 0);
745 704
746 // Inlining (mutates the flow graph) 705 // Inlining (mutates the flow graph)
747 if (FLAG_use_inlining) { 706 if (FLAG_use_inlining) {
748 TimelineDurationScope tds2(thread(), 707 TimelineDurationScope tds2(thread(),
749 compiler_timeline, 708 compiler_timeline,
750 "Inlining"); 709 "Inlining");
751 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); 710 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer);
752 // Propagate types to create more inlining opportunities. 711 // Propagate types to create more inlining opportunities.
753 FlowGraphTypePropagator::Propagate(flow_graph); 712 FlowGraphTypePropagator::Propagate(flow_graph);
754 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 713 DEBUG_ASSERT(flow_graph->VerifyUseLists());
755 714
756 // Use propagated class-ids to create more inlining opportunities. 715 // Use propagated class-ids to create more inlining opportunities.
757 optimizer.ApplyClassIds(); 716 optimizer.ApplyClassIds();
758 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 717 DEBUG_ASSERT(flow_graph->VerifyUseLists());
759 718
760 FlowGraphInliner inliner(flow_graph, 719 FlowGraphInliner inliner(flow_graph,
761 &inline_id_to_function, 720 &inline_id_to_function,
762 &caller_inline_id, 721 &caller_inline_id,
763 use_speculative_inlining, 722 use_speculative_inlining,
764 &inlining_black_list); 723 NULL);
765 inliner.Inline(); 724 inliner.Inline();
766 // Use lists are maintained and validated by the inliner. 725 // Use lists are maintained and validated by the inliner.
767 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 726 DEBUG_ASSERT(flow_graph->VerifyUseLists());
768 } 727 }
769 728
770 // Propagate types and eliminate more type tests. 729 // Propagate types and eliminate more type tests.
771 FlowGraphTypePropagator::Propagate(flow_graph); 730 FlowGraphTypePropagator::Propagate(flow_graph);
772 DEBUG_ASSERT(flow_graph->VerifyUseLists()); 731 DEBUG_ASSERT(flow_graph->VerifyUseLists());
773 732
774 { 733 {
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
1078 const Error& error = Error::Handle( 1037 const Error& error = Error::Handle(
1079 isolate()->object_store()->sticky_error()); 1038 isolate()->object_store()->sticky_error());
1080 1039
1081 if (error.raw() == Object::branch_offset_error().raw()) { 1040 if (error.raw() == Object::branch_offset_error().raw()) {
1082 // Compilation failed due to an out of range branch offset in the 1041 // Compilation failed due to an out of range branch offset in the
1083 // assembler. We try again (done = false) with far branches enabled. 1042 // assembler. We try again (done = false) with far branches enabled.
1084 done = false; 1043 done = false;
1085 ASSERT(!use_far_branches); 1044 ASSERT(!use_far_branches);
1086 use_far_branches = true; 1045 use_far_branches = true;
1087 } else if (error.raw() == Object::speculative_inlining_error().raw()) { 1046 } else if (error.raw() == Object::speculative_inlining_error().raw()) {
1088 // The return value of setjmp is the deopt id of the check instruction 1047 // Can only happen with precompilation.
1089 // that caused the bailout. 1048 UNREACHABLE();
1090 done = false;
1091 #if defined(DEBUG)
1092 ASSERT(FLAG_precompilation);
1093 ASSERT(use_speculative_inlining);
1094 for (intptr_t i = 0; i < inlining_black_list.length(); ++i) {
1095 ASSERT(inlining_black_list[i] != val);
1096 }
1097 #endif
1098 inlining_black_list.Add(val);
1099 const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts;
1100 if (inlining_black_list.length() >= max_attempts) {
1101 use_speculative_inlining = false;
1102 if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) {
1103 THR_Print("Disabled speculative inlining after %" Pd " attempts.\n",
1104 inlining_black_list.length());
1105 }
1106 }
1107 } else { 1049 } else {
1108 // If the error isn't due to an out of range branch offset, we don't 1050 // If the error isn't due to an out of range branch offset, we don't
1109 // try again (done = true), and indicate that we did not finish 1051 // try again (done = true), and indicate that we did not finish
1110 // compiling (is_compiled = false). 1052 // compiling (is_compiled = false).
1111 if (FLAG_trace_bailout) { 1053 if (FLAG_trace_bailout) {
1112 THR_Print("%s\n", error.ToErrorCString()); 1054 THR_Print("%s\n", error.ToErrorCString());
1113 } 1055 }
1114 done = true; 1056 done = true;
1115 } 1057 }
1116 1058
1117 // Clear the error if it was not a real error, but just a bailout. 1059 // Clear the error if it was not a real error, but just a bailout.
1118 if (error.IsLanguageError() && 1060 if (error.IsLanguageError() &&
1119 (LanguageError::Cast(error).kind() == Report::kBailout)) { 1061 (LanguageError::Cast(error).kind() == Report::kBailout)) {
1120 isolate()->object_store()->clear_sticky_error(); 1062 isolate()->object_store()->clear_sticky_error();
1121 } 1063 }
1122 is_compiled = false; 1064 is_compiled = false;
1123 } 1065 }
1124 // Reset global isolate state. 1066 // Reset global isolate state.
1125 thread()->set_deopt_id(prev_deopt_id); 1067 thread()->set_deopt_id(prev_deopt_id);
1126 } 1068 }
1127 return is_compiled; 1069 return is_compiled;
1128 } 1070 }
1129 1071
1130 1072
1131 static void DisassembleCode(const Function& function, bool optimized) { 1073 void Compiler::DisassembleCode(const Function& function, bool optimized) {
1132 const char* function_fullname = function.ToFullyQualifiedCString(); 1074 const char* function_fullname = function.ToFullyQualifiedCString();
1133 THR_Print("Code for %sfunction '%s' {\n", 1075 THR_Print("Code for %sfunction '%s' {\n",
1134 optimized ? "optimized " : "", 1076 optimized ? "optimized " : "",
1135 function_fullname); 1077 function_fullname);
1136 const Code& code = Code::Handle(function.CurrentCode()); 1078 const Code& code = Code::Handle(function.CurrentCode());
1137 code.Disassemble(); 1079 code.Disassemble();
1138 THR_Print("}\n"); 1080 THR_Print("}\n");
1139 1081
1140 THR_Print("Pointer offsets for function: {\n"); 1082 THR_Print("Pointer offsets for function: {\n");
1141 // Pointer offsets are stored in descending order. 1083 // Pointer offsets are stored in descending order.
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1287 function.raw()); 1229 function.raw());
1288 } 1230 }
1289 } 1231 }
1290 #endif 1232 #endif
1291 1233
1292 1234
1293 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, 1235 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
1294 const Function& function, 1236 const Function& function,
1295 bool optimized, 1237 bool optimized,
1296 intptr_t osr_id) { 1238 intptr_t osr_id) {
1297 // Check that we optimize if 'FLAG_precompilation' is set to true, 1239 ASSERT(!FLAG_precompilation);
1298 // except if the function is marked as not optimizable.
1299 ASSERT(!function.IsOptimizable() ||
1300 !FLAG_precompilation || optimized);
1301 ASSERT(!FLAG_precompilation || !function.HasCode());
1302 LongJumpScope jump; 1240 LongJumpScope jump;
1303 if (setjmp(*jump.Set()) == 0) { 1241 if (setjmp(*jump.Set()) == 0) {
1304 Thread* const thread = Thread::Current(); 1242 Thread* const thread = Thread::Current();
1305 Isolate* const isolate = thread->isolate(); 1243 Isolate* const isolate = thread->isolate();
1306 StackZone stack_zone(thread); 1244 StackZone stack_zone(thread);
1307 Zone* const zone = stack_zone.GetZone(); 1245 Zone* const zone = stack_zone.GetZone();
1308 const bool trace_compiler = 1246 const bool trace_compiler =
1309 FLAG_trace_compiler || 1247 FLAG_trace_compiler ||
1310 (FLAG_trace_optimizing_compiler && optimized); 1248 (FLAG_trace_optimizing_compiler && optimized);
1311 Timer per_compile_timer(trace_compiler, "Compilation time"); 1249 Timer per_compile_timer(trace_compiler, "Compilation time");
(...skipping 21 matching lines...) Expand all
1333 pipeline->ParseFunction(parsed_function); 1271 pipeline->ParseFunction(parsed_function);
1334 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); 1272 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed);
1335 INC_STAT(thread, 1273 INC_STAT(thread,
1336 num_func_tokens_compiled, 1274 num_func_tokens_compiled,
1337 num_tokens_after - num_tokens_before); 1275 num_tokens_after - num_tokens_before);
1338 } 1276 }
1339 1277
1340 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); 1278 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
1341 const bool success = helper.Compile(pipeline); 1279 const bool success = helper.Compile(pipeline);
1342 if (!success) { 1280 if (!success) {
1343 if (optimized && !FLAG_precompilation) { 1281 if (optimized) {
1344 // Optimizer bailed out. Disable optimizations and never try again. 1282 // Optimizer bailed out. Disable optimizations and never try again.
1345 if (trace_compiler) { 1283 if (trace_compiler) {
1346 THR_Print("--> disabling optimizations for '%s'\n", 1284 THR_Print("--> disabling optimizations for '%s'\n",
1347 function.ToFullyQualifiedCString()); 1285 function.ToFullyQualifiedCString());
1348 } else if (FLAG_trace_failed_optimization_attempts) { 1286 } else if (FLAG_trace_failed_optimization_attempts) {
1349 THR_Print("Cannot optimize: %s\n", 1287 THR_Print("Cannot optimize: %s\n",
1350 function.ToFullyQualifiedCString()); 1288 function.ToFullyQualifiedCString());
1351 } 1289 }
1352 function.SetIsOptimizable(false); 1290 function.SetIsOptimizable(false);
1353 return Error::null(); 1291 return Error::null();
(...skipping 15 matching lines...) Expand all
1369 THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n", 1307 THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
1370 function.ToFullyQualifiedCString(), 1308 function.ToFullyQualifiedCString(),
1371 Code::Handle(function.CurrentCode()).EntryPoint(), 1309 Code::Handle(function.CurrentCode()).EntryPoint(),
1372 Code::Handle(function.CurrentCode()).Size(), 1310 Code::Handle(function.CurrentCode()).Size(),
1373 per_compile_timer.TotalElapsedTime()); 1311 per_compile_timer.TotalElapsedTime());
1374 } 1312 }
1375 1313
1376 isolate->debugger()->NotifyCompilation(function); 1314 isolate->debugger()->NotifyCompilation(function);
1377 1315
1378 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { 1316 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) {
1379 DisassembleCode(function, optimized); 1317 Compiler::DisassembleCode(function, optimized);
1380 } else if (FLAG_disassemble_optimized && 1318 } else if (FLAG_disassemble_optimized &&
1381 optimized && 1319 optimized &&
1382 FlowGraphPrinter::ShouldPrint(function)) { 1320 FlowGraphPrinter::ShouldPrint(function)) {
1383 // TODO(fschneider): Print unoptimized code along with the optimized code. 1321 // TODO(fschneider): Print unoptimized code along with the optimized code.
1384 THR_Print("*** BEGIN CODE\n"); 1322 THR_Print("*** BEGIN CODE\n");
1385 DisassembleCode(function, true); 1323 Compiler::DisassembleCode(function, true);
1386 THR_Print("*** END CODE\n"); 1324 THR_Print("*** END CODE\n");
1387 } 1325 }
1388 #if defined(DEBUG) 1326 #if defined(DEBUG)
1389 CheckInliningIntervals(function); 1327 CheckInliningIntervals(function);
1390 #endif 1328 #endif
1391 return Error::null(); 1329 return Error::null();
1392 } else { 1330 } else {
1393 Thread* const thread = Thread::Current(); 1331 Thread* const thread = Thread::Current();
1394 Isolate* const isolate = thread->isolate(); 1332 Isolate* const isolate = thread->isolate();
1395 StackZone stack_zone(thread); 1333 StackZone stack_zone(thread);
1396 Error& error = Error::Handle(); 1334 Error& error = Error::Handle();
1397 // We got an error during compilation. 1335 // We got an error during compilation.
1398 error = isolate->object_store()->sticky_error(); 1336 error = isolate->object_store()->sticky_error();
1399 isolate->object_store()->clear_sticky_error(); 1337 isolate->object_store()->clear_sticky_error();
1400 // Unoptimized compilation or precompilation may encounter compile-time 1338 // Unoptimized compilation may encounter compile-time
1401 // errors, but regular optimized compilation should not. 1339 // errors, but regular optimized compilation should not.
1402 ASSERT(!optimized || FLAG_precompilation); 1340 ASSERT(!optimized);
1403 // Do not attempt to optimize functions that can cause errors. 1341 // Do not attempt to optimize functions that can cause errors.
1404 function.set_is_optimizable(false); 1342 function.set_is_optimizable(false);
1405 return error.raw(); 1343 return error.raw();
1406 } 1344 }
1407 UNREACHABLE(); 1345 UNREACHABLE();
1408 return Error::null(); 1346 return Error::null();
1409 } 1347 }
1410 1348
1411 1349
1412 RawError* Compiler::CompileFunction(Thread* thread, 1350 RawError* Compiler::CompileFunction(Thread* thread,
1413 const Function& function) { 1351 const Function& function) {
1352 #ifdef DART_PRECOMPILER
1353 if (FLAG_precompilation) {
1354 return Precompiler::CompileFunction(thread, function);
1355 }
1356 #endif
1414 Isolate* isolate = thread->isolate(); 1357 Isolate* isolate = thread->isolate();
1415 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); 1358 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
1416 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function); 1359 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function);
1417 1360
1418 if (!isolate->compilation_allowed()) { 1361 if (!isolate->compilation_allowed()) {
1419 FATAL3("Precompilation missed function %s (%s, %s)\n", 1362 FATAL3("Precompilation missed function %s (%s, %s)\n",
1420 function.ToLibNamePrefixedQualifiedCString(), 1363 function.ToLibNamePrefixedQualifiedCString(),
1421 function.token_pos().ToCString(), 1364 function.token_pos().ToCString(),
1422 Function::KindToCString(function.kind())); 1365 Function::KindToCString(function.kind()));
1423 } 1366 }
1424 1367
1425 CompilationPipeline* pipeline = 1368 CompilationPipeline* pipeline =
1426 CompilationPipeline::New(thread->zone(), function); 1369 CompilationPipeline::New(thread->zone(), function);
1427 1370
1428 const bool optimized =
1429 FLAG_precompilation && function.IsOptimizable();
1430
1431 return CompileFunctionHelper(pipeline, 1371 return CompileFunctionHelper(pipeline,
1432 function, 1372 function,
1433 optimized, 1373 /* optimized = */ false,
1434 kNoOSRDeoptId); 1374 kNoOSRDeoptId);
1435 } 1375 }
1436 1376
1437 1377
1438 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, 1378 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
1439 const Function& function) { 1379 const Function& function) {
1440 if (function.unoptimized_code() != Object::null()) { 1380 if (function.unoptimized_code() != Object::null()) {
1441 return Error::null(); 1381 return Error::null();
1442 } 1382 }
1443 Code& original_code = Code::ZoneHandle(thread->zone()); 1383 Code& original_code = Code::ZoneHandle(thread->zone());
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1558 return error.raw(); 1498 return error.raw();
1559 } 1499 }
1560 func.ClearICDataArray(); 1500 func.ClearICDataArray();
1561 func.ClearCode(); 1501 func.ClearCode();
1562 } 1502 }
1563 } 1503 }
1564 return error.raw(); 1504 return error.raw();
1565 } 1505 }
1566 1506
1567 1507
1568 void Compiler::CompileStaticInitializer(const Field& field) {
1569 ASSERT(field.is_static());
1570 if (field.HasPrecompiledInitializer()) {
1571 // TODO(rmacnak): Investigate why this happens for _enum_names.
1572 OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
1573 field.ToCString());
1574 return;
1575 }
1576 Thread* thread = Thread::Current();
1577 StackZone zone(thread);
1578
1579 ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
1580
1581 parsed_function->AllocateVariables();
1582 // Non-optimized code generator.
1583 DartCompilationPipeline pipeline;
1584 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
1585 helper.Compile(&pipeline);
1586 const Function& initializer = parsed_function->function();
1587 field.SetPrecompiledInitializer(initializer);
1588 }
1589
1590
1591 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { 1508 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
1509 #ifdef DART_PRECOMPILER
1510 if (FLAG_precompilation) {
1511 return Precompiler::EvaluateStaticInitializer(field);
1512 }
1513 #endif
1592 ASSERT(field.is_static()); 1514 ASSERT(field.is_static());
1593 // The VM sets the field's value to transiton_sentinel prior to 1515 // The VM sets the field's value to transiton_sentinel prior to
1594 // evaluating the initializer value. 1516 // evaluating the initializer value.
1595 ASSERT(field.StaticValue() == Object::transition_sentinel().raw()); 1517 ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
1596 LongJumpScope jump; 1518 LongJumpScope jump;
1597 if (setjmp(*jump.Set()) == 0) { 1519 if (setjmp(*jump.Set()) == 0) {
1598 // Under precompilation, the initializer may have already been compiled, in 1520 // Under lazy compilation initializer has not yet been created, so create
1599 // which case use it. Under lazy compilation or early in precompilation, the 1521 // it now, but don't bother remembering it because it won't be used again.
1600 // initializer has not yet been created, so create it now, but don't bother 1522 ASSERT(!field.HasPrecompiledInitializer());
1601 // remembering it because it won't be used again. 1523 Thread* const thread = Thread::Current();
1602 Function& initializer = Function::Handle(); 1524 StackZone zone(thread);
1603 if (!field.HasPrecompiledInitializer()) { 1525 ParsedFunction* parsed_function =
1604 Thread* const thread = Thread::Current(); 1526 Parser::ParseStaticFieldInitializer(field);
1605 StackZone zone(thread);
1606 ParsedFunction* parsed_function =
1607 Parser::ParseStaticFieldInitializer(field);
1608 1527
1609 parsed_function->AllocateVariables(); 1528 parsed_function->AllocateVariables();
1610 // Non-optimized code generator. 1529 // Non-optimized code generator.
1611 DartCompilationPipeline pipeline; 1530 DartCompilationPipeline pipeline;
1612 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); 1531 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
1613 helper.Compile(&pipeline); 1532 helper.Compile(&pipeline);
1614 initializer = parsed_function->function().raw(); 1533 const Function& initializer =
1615 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( 1534 Function::Handle(parsed_function->function().raw());
1616 Object::empty_var_descriptors()); 1535 Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
1617 } else { 1536 Object::empty_var_descriptors());
1618 initializer ^= field.PrecompiledInitializer();
1619 }
1620 // Invoke the function to evaluate the expression. 1537 // Invoke the function to evaluate the expression.
1621 return DartEntry::InvokeFunction(initializer, Object::empty_array()); 1538 return DartEntry::InvokeFunction(initializer, Object::empty_array());
1622 } else { 1539 } else {
1623 Thread* const thread = Thread::Current(); 1540 Thread* const thread = Thread::Current();
1624 Isolate* const isolate = thread->isolate(); 1541 Isolate* const isolate = thread->isolate();
1625 StackZone zone(thread); 1542 StackZone zone(thread);
1626 const Error& error = 1543 const Error& error =
1627 Error::Handle(thread->zone(), isolate->object_store()->sticky_error()); 1544 Error::Handle(thread->zone(), isolate->object_store()->sticky_error());
1628 isolate->object_store()->clear_sticky_error(); 1545 isolate->object_store()->clear_sticky_error();
1629 return error.raw(); 1546 return error.raw();
1630 } 1547 }
1631 UNREACHABLE(); 1548 UNREACHABLE();
1632 return Object::null(); 1549 return Object::null();
1633 } 1550 }
1634 1551
1635 1552
1636 1553
1637 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { 1554 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
1555 #ifdef DART_PRECOMPILER
1556 if (FLAG_precompilation) {
1557 return Precompiler::ExecuteOnce(fragment);
1558 }
1559 #endif
1638 LongJumpScope jump; 1560 LongJumpScope jump;
1639 if (setjmp(*jump.Set()) == 0) { 1561 if (setjmp(*jump.Set()) == 0) {
1640 Thread* const thread = Thread::Current(); 1562 Thread* const thread = Thread::Current();
1641 if (FLAG_trace_compiler) { 1563 if (FLAG_trace_compiler) {
1642 THR_Print("compiling expression: "); 1564 THR_Print("compiling expression: ");
1643 AstPrinter::PrintNode(fragment); 1565 AstPrinter::PrintNode(fragment);
1644 } 1566 }
1645 1567
1646 // Create a dummy function object for the code generator. 1568 // Create a dummy function object for the code generator.
1647 // The function needs to be associated with a named Class: the interface 1569 // The function needs to be associated with a named Class: the interface
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
1998 UNREACHABLE(); 1920 UNREACHABLE();
1999 } 1921 }
2000 1922
2001 1923
2002 RawError* Compiler::CompileAllFunctions(const Class& cls) { 1924 RawError* Compiler::CompileAllFunctions(const Class& cls) {
2003 UNREACHABLE(); 1925 UNREACHABLE();
2004 return Error::null(); 1926 return Error::null();
2005 } 1927 }
2006 1928
2007 1929
2008 void Compiler::CompileStaticInitializer(const Field& field) {
2009 UNREACHABLE();
2010 }
2011
2012
2013 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { 1930 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
2014 ASSERT(field.HasPrecompiledInitializer()); 1931 ASSERT(field.HasPrecompiledInitializer());
2015 const Function& initializer = 1932 const Function& initializer =
2016 Function::Handle(field.PrecompiledInitializer()); 1933 Function::Handle(field.PrecompiledInitializer());
2017 return DartEntry::InvokeFunction(initializer, Object::empty_array()); 1934 return DartEntry::InvokeFunction(initializer, Object::empty_array());
2018 } 1935 }
2019 1936
2020 1937
2021
2022 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { 1938 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
2023 UNREACHABLE(); 1939 UNREACHABLE();
2024 return Object::null(); 1940 return Object::null();
2025 } 1941 }
2026 1942
2027 1943
2028 void BackgroundCompiler::CompileOptimized(const Function& function) { 1944 void BackgroundCompiler::CompileOptimized(const Function& function) {
2029 UNREACHABLE(); 1945 UNREACHABLE();
2030 } 1946 }
2031 1947
2032 1948
2033 void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) { 1949 void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) {
2034 UNREACHABLE(); 1950 UNREACHABLE();
2035 } 1951 }
2036 1952
2037 1953
2038 void BackgroundCompiler::Stop(BackgroundCompiler* task) { 1954 void BackgroundCompiler::Stop(BackgroundCompiler* task) {
2039 UNREACHABLE(); 1955 UNREACHABLE();
2040 } 1956 }
2041 1957
2042 1958
2043 void BackgroundCompiler::EnsureInit(Thread* thread) { 1959 void BackgroundCompiler::EnsureInit(Thread* thread) {
2044 UNREACHABLE(); 1960 UNREACHABLE();
2045 } 1961 }
2046 1962
2047 #endif // DART_PRECOMPILED_RUNTIME 1963 #endif // DART_PRECOMPILED_RUNTIME
2048 1964
2049 } // namespace dart 1965 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/compiler.h ('k') | runtime/vm/dart_api_impl.cc » ('j') | runtime/vm/precompiler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698