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 29 matching lines...) Expand all Loading... |
40 #include "vm/regexp_parser.h" | 40 #include "vm/regexp_parser.h" |
41 #include "vm/regexp_assembler.h" | 41 #include "vm/regexp_assembler.h" |
42 #include "vm/symbols.h" | 42 #include "vm/symbols.h" |
43 #include "vm/tags.h" | 43 #include "vm/tags.h" |
44 #include "vm/thread_registry.h" | 44 #include "vm/thread_registry.h" |
45 #include "vm/timeline.h" | 45 #include "vm/timeline.h" |
46 #include "vm/timer.h" | 46 #include "vm/timer.h" |
47 | 47 |
48 namespace dart { | 48 namespace dart { |
49 | 49 |
50 DEFINE_FLAG(bool, allocation_sinking, true, | 50 DEFINE_FLAG(bool, |
51 "Attempt to sink temporary allocations to side exits"); | 51 allocation_sinking, |
52 DEFINE_FLAG(bool, common_subexpression_elimination, true, | 52 true, |
53 "Do common subexpression elimination."); | 53 "Attempt to sink temporary allocations to side exits"); |
54 DEFINE_FLAG(bool, constant_propagation, true, | 54 DEFINE_FLAG(bool, |
| 55 common_subexpression_elimination, |
| 56 true, |
| 57 "Do common subexpression elimination."); |
| 58 DEFINE_FLAG( |
| 59 bool, |
| 60 constant_propagation, |
| 61 true, |
55 "Do conditional constant propagation/unreachable code elimination."); | 62 "Do conditional constant propagation/unreachable code elimination."); |
56 DEFINE_FLAG(int, max_deoptimization_counter_threshold, 16, | 63 DEFINE_FLAG( |
| 64 int, |
| 65 max_deoptimization_counter_threshold, |
| 66 16, |
57 "How many times we allow deoptimization before we disallow optimization."); | 67 "How many times we allow deoptimization before we disallow optimization."); |
58 DEFINE_FLAG(bool, loop_invariant_code_motion, true, | 68 DEFINE_FLAG(bool, |
59 "Do loop invariant code motion."); | 69 loop_invariant_code_motion, |
| 70 true, |
| 71 "Do loop invariant code motion."); |
60 DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function"); | 72 DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function"); |
61 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 73 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
62 DEFINE_FLAG(bool, print_flow_graph_optimized, false, | 74 DEFINE_FLAG(bool, |
63 "Print the IR flow graph when optimizing."); | 75 print_flow_graph_optimized, |
64 DEFINE_FLAG(bool, print_ic_data_map, false, | 76 false, |
65 "Print the deopt-id to ICData map in optimizing compiler."); | 77 "Print the IR flow graph when optimizing."); |
| 78 DEFINE_FLAG(bool, |
| 79 print_ic_data_map, |
| 80 false, |
| 81 "Print the deopt-id to ICData map in optimizing compiler."); |
66 DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map."); | 82 DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map."); |
67 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis"); | 83 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis"); |
68 DEFINE_FLAG(bool, stress_test_background_compilation, false, | 84 DEFINE_FLAG(bool, |
69 "Keep background compiler running all the time"); | 85 stress_test_background_compilation, |
70 DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false, | 86 false, |
71 "Debugging: stops program if deoptimizing same function too often"); | 87 "Keep background compiler running all the time"); |
| 88 DEFINE_FLAG(bool, |
| 89 stop_on_excessive_deoptimization, |
| 90 false, |
| 91 "Debugging: stops program if deoptimizing same function too often"); |
72 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); | 92 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); |
73 DEFINE_FLAG(bool, trace_failed_optimization_attempts, false, | 93 DEFINE_FLAG(bool, |
74 "Traces all failed optimization attempts"); | 94 trace_failed_optimization_attempts, |
75 DEFINE_FLAG(bool, trace_optimizing_compiler, false, | 95 false, |
76 "Trace only optimizing compiler operations."); | 96 "Traces all failed optimization attempts"); |
| 97 DEFINE_FLAG(bool, |
| 98 trace_optimizing_compiler, |
| 99 false, |
| 100 "Trace only optimizing compiler operations."); |
77 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); | 101 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); |
78 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); | 102 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); |
79 DEFINE_FLAG(bool, verify_compiler, false, | 103 DEFINE_FLAG(bool, |
80 "Enable compiler verification assertions"); | 104 verify_compiler, |
| 105 false, |
| 106 "Enable compiler verification assertions"); |
81 | 107 |
82 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); | 108 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); |
83 DECLARE_FLAG(bool, trace_failed_optimization_attempts); | 109 DECLARE_FLAG(bool, trace_failed_optimization_attempts); |
84 DECLARE_FLAG(bool, trace_irregexp); | 110 DECLARE_FLAG(bool, trace_irregexp); |
85 | 111 |
86 | 112 |
87 #ifndef DART_PRECOMPILED_RUNTIME | 113 #ifndef DART_PRECOMPILED_RUNTIME |
88 | 114 |
89 | 115 |
90 bool UseKernelFrontEndFor(ParsedFunction* parsed_function) { | 116 bool UseKernelFrontEndFor(ParsedFunction* parsed_function) { |
(...skipping 13 matching lines...) Expand all Loading... |
104 | 130 |
105 | 131 |
106 FlowGraph* DartCompilationPipeline::BuildFlowGraph( | 132 FlowGraph* DartCompilationPipeline::BuildFlowGraph( |
107 Zone* zone, | 133 Zone* zone, |
108 ParsedFunction* parsed_function, | 134 ParsedFunction* parsed_function, |
109 const ZoneGrowableArray<const ICData*>& ic_data_array, | 135 const ZoneGrowableArray<const ICData*>& ic_data_array, |
110 intptr_t osr_id) { | 136 intptr_t osr_id) { |
111 if (UseKernelFrontEndFor(parsed_function)) { | 137 if (UseKernelFrontEndFor(parsed_function)) { |
112 kernel::TreeNode* node = static_cast<kernel::TreeNode*>( | 138 kernel::TreeNode* node = static_cast<kernel::TreeNode*>( |
113 parsed_function->function().kernel_function()); | 139 parsed_function->function().kernel_function()); |
114 kernel::FlowGraphBuilder builder( | 140 kernel::FlowGraphBuilder builder(node, parsed_function, ic_data_array, NULL, |
115 node, parsed_function, ic_data_array, NULL, osr_id); | 141 osr_id); |
116 FlowGraph* graph = builder.BuildGraph(); | 142 FlowGraph* graph = builder.BuildGraph(); |
117 ASSERT(graph != NULL); | 143 ASSERT(graph != NULL); |
118 return graph; | 144 return graph; |
119 } | 145 } |
120 FlowGraphBuilder builder(*parsed_function, | 146 FlowGraphBuilder builder(*parsed_function, ic_data_array, |
121 ic_data_array, | |
122 NULL, // NULL = not inlining. | 147 NULL, // NULL = not inlining. |
123 osr_id); | 148 osr_id); |
124 | 149 |
125 return builder.BuildGraph(); | 150 return builder.BuildGraph(); |
126 } | 151 } |
127 | 152 |
128 | 153 |
129 void DartCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) { } | 154 void DartCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) {} |
130 | 155 |
131 | 156 |
132 void IrregexpCompilationPipeline::ParseFunction( | 157 void IrregexpCompilationPipeline::ParseFunction( |
133 ParsedFunction* parsed_function) { | 158 ParsedFunction* parsed_function) { |
134 RegExpParser::ParseFunction(parsed_function); | 159 RegExpParser::ParseFunction(parsed_function); |
135 // Variables are allocated after compilation. | 160 // Variables are allocated after compilation. |
136 } | 161 } |
137 | 162 |
138 | 163 |
139 FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph( | 164 FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph( |
140 Zone* zone, | 165 Zone* zone, |
141 ParsedFunction* parsed_function, | 166 ParsedFunction* parsed_function, |
142 const ZoneGrowableArray<const ICData*>& ic_data_array, | 167 const ZoneGrowableArray<const ICData*>& ic_data_array, |
143 intptr_t osr_id) { | 168 intptr_t osr_id) { |
144 // Compile to the dart IR. | 169 // Compile to the dart IR. |
145 RegExpEngine::CompilationResult result = | 170 RegExpEngine::CompilationResult result = RegExpEngine::CompileIR( |
146 RegExpEngine::CompileIR(parsed_function->regexp_compile_data(), | 171 parsed_function->regexp_compile_data(), parsed_function, ic_data_array); |
147 parsed_function, | |
148 ic_data_array); | |
149 backtrack_goto_ = result.backtrack_goto; | 172 backtrack_goto_ = result.backtrack_goto; |
150 | 173 |
151 // Allocate variables now that we know the number of locals. | 174 // Allocate variables now that we know the number of locals. |
152 parsed_function->AllocateIrregexpVariables(result.num_stack_locals); | 175 parsed_function->AllocateIrregexpVariables(result.num_stack_locals); |
153 | 176 |
154 // Build the flow graph. | 177 // Build the flow graph. |
155 FlowGraphBuilder builder(*parsed_function, | 178 FlowGraphBuilder builder(*parsed_function, ic_data_array, |
156 ic_data_array, | |
157 NULL, // NULL = not inlining. | 179 NULL, // NULL = not inlining. |
158 osr_id); | 180 osr_id); |
159 | 181 |
160 return new(zone) FlowGraph(*parsed_function, | 182 return new (zone) |
161 result.graph_entry, | 183 FlowGraph(*parsed_function, result.graph_entry, result.num_blocks); |
162 result.num_blocks); | |
163 } | 184 } |
164 | 185 |
165 | 186 |
166 void IrregexpCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) { | 187 void IrregexpCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) { |
167 backtrack_goto_->ComputeOffsetTable(); | 188 backtrack_goto_->ComputeOffsetTable(); |
168 } | 189 } |
169 | 190 |
170 | 191 |
171 CompilationPipeline* CompilationPipeline::New(Zone* zone, | 192 CompilationPipeline* CompilationPipeline::New(Zone* zone, |
172 const Function& function) { | 193 const Function& function) { |
173 if (function.IsIrregexpFunction()) { | 194 if (function.IsIrregexpFunction()) { |
174 return new(zone) IrregexpCompilationPipeline(); | 195 return new (zone) IrregexpCompilationPipeline(); |
175 } else { | 196 } else { |
176 return new(zone) DartCompilationPipeline(); | 197 return new (zone) DartCompilationPipeline(); |
177 } | 198 } |
178 } | 199 } |
179 | 200 |
180 | 201 |
181 // Compile a function. Should call only if the function has not been compiled. | 202 // Compile a function. Should call only if the function has not been compiled. |
182 // Arg0: function object. | 203 // Arg0: function object. |
183 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { | 204 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { |
184 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 205 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
185 ASSERT(!function.HasCode()); | 206 ASSERT(!function.HasCode()); |
186 const Error& error = | 207 const Error& error = |
(...skipping 17 matching lines...) Expand all Loading... |
204 // so do not optimize the function. | 225 // so do not optimize the function. |
205 function.set_usage_counter(0); | 226 function.set_usage_counter(0); |
206 return false; | 227 return false; |
207 } | 228 } |
208 } | 229 } |
209 if (function.deoptimization_counter() >= | 230 if (function.deoptimization_counter() >= |
210 FLAG_max_deoptimization_counter_threshold) { | 231 FLAG_max_deoptimization_counter_threshold) { |
211 if (FLAG_trace_failed_optimization_attempts || | 232 if (FLAG_trace_failed_optimization_attempts || |
212 FLAG_stop_on_excessive_deoptimization) { | 233 FLAG_stop_on_excessive_deoptimization) { |
213 THR_Print("Too many deoptimizations: %s\n", | 234 THR_Print("Too many deoptimizations: %s\n", |
214 function.ToFullyQualifiedCString()); | 235 function.ToFullyQualifiedCString()); |
215 if (FLAG_stop_on_excessive_deoptimization) { | 236 if (FLAG_stop_on_excessive_deoptimization) { |
216 FATAL("Stop on excessive deoptimization"); | 237 FATAL("Stop on excessive deoptimization"); |
217 } | 238 } |
218 } | 239 } |
219 // The function will not be optimized any longer. This situation can occur | 240 // The function will not be optimized any longer. This situation can occur |
220 // mostly with small optimization counter thresholds. | 241 // mostly with small optimization counter thresholds. |
221 function.SetIsOptimizable(false); | 242 function.SetIsOptimizable(false); |
222 function.set_usage_counter(INT_MIN); | 243 function.set_usage_counter(INT_MIN); |
223 return false; | 244 return false; |
224 } | 245 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 return Error::null(); | 366 return Error::null(); |
346 } | 367 } |
347 // If the class is already marked for parsing return immediately. | 368 // If the class is already marked for parsing return immediately. |
348 if (cls.is_marked_for_parsing()) { | 369 if (cls.is_marked_for_parsing()) { |
349 return Error::null(); | 370 return Error::null(); |
350 } | 371 } |
351 // If the class is a typedef class there is no need to try and | 372 // If the class is a typedef class there is no need to try and |
352 // compile it. Just finalize it directly. | 373 // compile it. Just finalize it directly. |
353 if (cls.IsTypedefClass()) { | 374 if (cls.IsTypedefClass()) { |
354 #if defined(DEBUG) | 375 #if defined(DEBUG) |
355 const Class& closure_cls = Class::Handle( | 376 const Class& closure_cls = |
356 Isolate::Current()->object_store()->closure_class()); | 377 Class::Handle(Isolate::Current()->object_store()->closure_class()); |
357 ASSERT(closure_cls.is_finalized()); | 378 ASSERT(closure_cls.is_finalized()); |
358 #endif | 379 #endif |
359 LongJumpScope jump; | 380 LongJumpScope jump; |
360 if (setjmp(*jump.Set()) == 0) { | 381 if (setjmp(*jump.Set()) == 0) { |
361 ClassFinalizer::FinalizeClass(cls); | 382 ClassFinalizer::FinalizeClass(cls); |
362 return Error::null(); | 383 return Error::null(); |
363 } else { | 384 } else { |
364 Thread* thread = Thread::Current(); | 385 Thread* thread = Thread::Current(); |
365 Error& error = Error::Handle(thread->zone()); | 386 Error& error = Error::Handle(thread->zone()); |
366 error = thread->sticky_error(); | 387 error = thread->sticky_error(); |
367 thread->clear_sticky_error(); | 388 thread->clear_sticky_error(); |
368 return error.raw(); | 389 return error.raw(); |
369 } | 390 } |
370 } | 391 } |
371 | 392 |
372 Thread* const thread = Thread::Current(); | 393 Thread* const thread = Thread::Current(); |
373 StackZone zone(thread); | 394 StackZone zone(thread); |
374 NOT_IN_PRODUCT( | 395 #if !defined(PRODUCT) |
375 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); | 396 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); |
376 TimelineDurationScope tds(thread, | 397 TimelineDurationScope tds(thread, Timeline::GetCompilerStream(), |
377 Timeline::GetCompilerStream(), | |
378 "CompileClass"); | 398 "CompileClass"); |
379 if (tds.enabled()) { | 399 if (tds.enabled()) { |
380 tds.SetNumArguments(1); | 400 tds.SetNumArguments(1); |
381 tds.CopyArgument(0, "class", cls.ToCString()); | 401 tds.CopyArgument(0, "class", cls.ToCString()); |
382 } | 402 } |
383 ) // !PRODUCT | 403 #endif // !defined(PRODUCT) |
384 | 404 |
385 // We remember all the classes that are being compiled in these lists. This | 405 // We remember all the classes that are being compiled in these lists. This |
386 // also allows us to reset the marked_for_parsing state in case we see an | 406 // also allows us to reset the marked_for_parsing state in case we see an |
387 // error. | 407 // error. |
388 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); | 408 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); |
389 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); | 409 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); |
390 | 410 |
391 // Parse the class and all the interfaces it implements and super classes. | 411 // Parse the class and all the interfaces it implements and super classes. |
392 LongJumpScope jump; | 412 LongJumpScope jump; |
393 if (setjmp(*jump.Set()) == 0) { | 413 if (setjmp(*jump.Set()) == 0) { |
(...skipping 11 matching lines...) Expand all Loading... |
405 // exists to the corresponding lists. | 425 // exists to the corresponding lists. |
406 // NOTE: The parse_list array keeps growing as more classes are added | 426 // NOTE: The parse_list array keeps growing as more classes are added |
407 // to it by AddRelatedClassesToList. It is not OK to hoist | 427 // to it by AddRelatedClassesToList. It is not OK to hoist |
408 // parse_list.Length() into a local variable and iterate using the local | 428 // parse_list.Length() into a local variable and iterate using the local |
409 // variable. | 429 // variable. |
410 for (intptr_t i = 0; i < parse_list.length(); i++) { | 430 for (intptr_t i = 0; i < parse_list.length(); i++) { |
411 AddRelatedClassesToList(parse_list.At(i), &parse_list, &patch_list); | 431 AddRelatedClassesToList(parse_list.At(i), &parse_list, &patch_list); |
412 } | 432 } |
413 | 433 |
414 // Parse all the classes that have been added above. | 434 // Parse all the classes that have been added above. |
415 for (intptr_t i = (parse_list.length() - 1); i >=0 ; i--) { | 435 for (intptr_t i = (parse_list.length() - 1); i >= 0; i--) { |
416 const Class& parse_class = parse_list.At(i); | 436 const Class& parse_class = parse_list.At(i); |
417 ASSERT(!parse_class.IsNull()); | 437 ASSERT(!parse_class.IsNull()); |
418 Parser::ParseClass(parse_class); | 438 Parser::ParseClass(parse_class); |
419 } | 439 } |
420 | 440 |
421 // Parse all the patch classes that have been added above. | 441 // Parse all the patch classes that have been added above. |
422 for (intptr_t i = 0; i < patch_list.length(); i++) { | 442 for (intptr_t i = 0; i < patch_list.length(); i++) { |
423 const Class& parse_class = patch_list.At(i); | 443 const Class& parse_class = patch_list.At(i); |
424 ASSERT(!parse_class.IsNull()); | 444 ASSERT(!parse_class.IsNull()); |
425 Parser::ParseClass(parse_class); | 445 Parser::ParseClass(parse_class); |
426 } | 446 } |
427 | 447 |
428 // Finalize these classes. | 448 // Finalize these classes. |
429 for (intptr_t i = (parse_list.length() - 1); i >=0 ; i--) { | 449 for (intptr_t i = (parse_list.length() - 1); i >= 0; i--) { |
430 const Class& parse_class = parse_list.At(i); | 450 const Class& parse_class = parse_list.At(i); |
431 ASSERT(!parse_class.IsNull()); | 451 ASSERT(!parse_class.IsNull()); |
432 ClassFinalizer::FinalizeClass(parse_class); | 452 ClassFinalizer::FinalizeClass(parse_class); |
433 parse_class.reset_is_marked_for_parsing(); | 453 parse_class.reset_is_marked_for_parsing(); |
434 } | 454 } |
435 for (intptr_t i = (patch_list.length() - 1); i >=0 ; i--) { | 455 for (intptr_t i = (patch_list.length() - 1); i >= 0; i--) { |
436 const Class& parse_class = patch_list.At(i); | 456 const Class& parse_class = patch_list.At(i); |
437 ASSERT(!parse_class.IsNull()); | 457 ASSERT(!parse_class.IsNull()); |
438 ClassFinalizer::FinalizeClass(parse_class); | 458 ClassFinalizer::FinalizeClass(parse_class); |
439 parse_class.reset_is_marked_for_parsing(); | 459 parse_class.reset_is_marked_for_parsing(); |
440 } | 460 } |
441 | 461 |
442 return Error::null(); | 462 return Error::null(); |
443 } else { | 463 } else { |
444 // Reset the marked for parsing flags. | 464 // Reset the marked for parsing flags. |
445 for (intptr_t i = 0; i < parse_list.length(); i++) { | 465 for (intptr_t i = 0; i < parse_list.length(); i++) { |
(...skipping 21 matching lines...) Expand all Loading... |
467 class CompileParsedFunctionHelper : public ValueObject { | 487 class CompileParsedFunctionHelper : public ValueObject { |
468 public: | 488 public: |
469 CompileParsedFunctionHelper(ParsedFunction* parsed_function, | 489 CompileParsedFunctionHelper(ParsedFunction* parsed_function, |
470 bool optimized, | 490 bool optimized, |
471 intptr_t osr_id) | 491 intptr_t osr_id) |
472 : parsed_function_(parsed_function), | 492 : parsed_function_(parsed_function), |
473 optimized_(optimized), | 493 optimized_(optimized), |
474 osr_id_(osr_id), | 494 osr_id_(osr_id), |
475 thread_(Thread::Current()), | 495 thread_(Thread::Current()), |
476 loading_invalidation_gen_at_start_( | 496 loading_invalidation_gen_at_start_( |
477 isolate()->loading_invalidation_gen()) { | 497 isolate()->loading_invalidation_gen()) {} |
478 } | |
479 | 498 |
480 bool Compile(CompilationPipeline* pipeline); | 499 bool Compile(CompilationPipeline* pipeline); |
481 | 500 |
482 private: | 501 private: |
483 ParsedFunction* parsed_function() const { return parsed_function_; } | 502 ParsedFunction* parsed_function() const { return parsed_function_; } |
484 bool optimized() const { return optimized_; } | 503 bool optimized() const { return optimized_; } |
485 intptr_t osr_id() const { return osr_id_; } | 504 intptr_t osr_id() const { return osr_id_; } |
486 Thread* thread() const { return thread_; } | 505 Thread* thread() const { return thread_; } |
487 Isolate* isolate() const { return thread_->isolate(); } | 506 Isolate* isolate() const { return thread_->isolate(); } |
488 intptr_t loading_invalidation_gen_at_start() const { | 507 intptr_t loading_invalidation_gen_at_start() const { |
(...skipping 24 matching lines...) Expand all Loading... |
513 | 532 |
514 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer); | 533 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer); |
515 // CreateDeoptInfo uses the object pool and needs to be done before | 534 // CreateDeoptInfo uses the object pool and needs to be done before |
516 // FinalizeCode. | 535 // FinalizeCode. |
517 const Array& deopt_info_array = | 536 const Array& deopt_info_array = |
518 Array::Handle(zone, graph_compiler->CreateDeoptInfo(assembler)); | 537 Array::Handle(zone, graph_compiler->CreateDeoptInfo(assembler)); |
519 INC_STAT(thread(), total_code_size, | 538 INC_STAT(thread(), total_code_size, |
520 deopt_info_array.Length() * sizeof(uword)); | 539 deopt_info_array.Length() * sizeof(uword)); |
521 // Allocates instruction object. Since this occurs only at safepoint, | 540 // Allocates instruction object. Since this occurs only at safepoint, |
522 // there can be no concurrent access to the instruction page. | 541 // there can be no concurrent access to the instruction page. |
523 const Code& code = Code::Handle( | 542 const Code& code = |
524 Code::FinalizeCode(function, assembler, optimized())); | 543 Code::Handle(Code::FinalizeCode(function, assembler, optimized())); |
525 code.set_is_optimized(optimized()); | 544 code.set_is_optimized(optimized()); |
526 code.set_owner(function); | 545 code.set_owner(function); |
527 if (!function.IsOptimizable()) { | 546 if (!function.IsOptimizable()) { |
528 // A function with huge unoptimized code can become non-optimizable | 547 // A function with huge unoptimized code can become non-optimizable |
529 // after generating unoptimized code. | 548 // after generating unoptimized code. |
530 function.set_usage_counter(INT_MIN); | 549 function.set_usage_counter(INT_MIN); |
531 } | 550 } |
532 | 551 |
533 const Array& intervals = graph_compiler->inlined_code_intervals(); | 552 const Array& intervals = graph_compiler->inlined_code_intervals(); |
534 INC_STAT(thread(), total_code_size, | 553 INC_STAT(thread(), total_code_size, intervals.Length() * sizeof(uword)); |
535 intervals.Length() * sizeof(uword)); | |
536 code.SetInlinedIntervals(intervals); | 554 code.SetInlinedIntervals(intervals); |
537 | 555 |
538 const Array& inlined_id_array = | 556 const Array& inlined_id_array = |
539 Array::Handle(zone, graph_compiler->InliningIdToFunction()); | 557 Array::Handle(zone, graph_compiler->InliningIdToFunction()); |
540 INC_STAT(thread(), total_code_size, | 558 INC_STAT(thread(), total_code_size, |
541 inlined_id_array.Length() * sizeof(uword)); | 559 inlined_id_array.Length() * sizeof(uword)); |
542 code.SetInlinedIdToFunction(inlined_id_array); | 560 code.SetInlinedIdToFunction(inlined_id_array); |
543 | 561 |
544 const Array& caller_inlining_id_map_array = | 562 const Array& caller_inlining_id_map_array = |
545 Array::Handle(zone, graph_compiler->CallerInliningIdMap()); | 563 Array::Handle(zone, graph_compiler->CallerInliningIdMap()); |
546 INC_STAT(thread(), total_code_size, | 564 INC_STAT(thread(), total_code_size, |
547 caller_inlining_id_map_array.Length() * sizeof(uword)); | 565 caller_inlining_id_map_array.Length() * sizeof(uword)); |
548 code.SetInlinedCallerIdMap(caller_inlining_id_map_array); | 566 code.SetInlinedCallerIdMap(caller_inlining_id_map_array); |
549 | 567 |
550 const Array& inlined_id_to_token_pos = | 568 const Array& inlined_id_to_token_pos = |
551 Array::Handle(zone, graph_compiler->InliningIdToTokenPos()); | 569 Array::Handle(zone, graph_compiler->InliningIdToTokenPos()); |
552 INC_STAT(thread(), total_code_size, | 570 INC_STAT(thread(), total_code_size, |
553 inlined_id_to_token_pos.Length() * sizeof(uword)); | 571 inlined_id_to_token_pos.Length() * sizeof(uword)); |
554 code.SetInlinedIdToTokenPos(inlined_id_to_token_pos); | 572 code.SetInlinedIdToTokenPos(inlined_id_to_token_pos); |
555 | 573 |
556 graph_compiler->FinalizePcDescriptors(code); | 574 graph_compiler->FinalizePcDescriptors(code); |
557 code.set_deopt_info_array(deopt_info_array); | 575 code.set_deopt_info_array(deopt_info_array); |
558 | 576 |
559 graph_compiler->FinalizeStackmaps(code); | 577 graph_compiler->FinalizeStackmaps(code); |
560 graph_compiler->FinalizeVarDescriptors(code); | 578 graph_compiler->FinalizeVarDescriptors(code); |
561 graph_compiler->FinalizeExceptionHandlers(code); | 579 graph_compiler->FinalizeExceptionHandlers(code); |
562 graph_compiler->FinalizeStaticCallTargetsTable(code); | 580 graph_compiler->FinalizeStaticCallTargetsTable(code); |
563 | 581 |
564 NOT_IN_PRODUCT( | 582 #if !defined(PRODUCT) |
565 // Set the code source map after setting the inlined information because | 583 // Set the code source map after setting the inlined information because |
566 // we use the inlined information when printing. | 584 // we use the inlined information when printing. |
567 const CodeSourceMap& code_source_map = | 585 const CodeSourceMap& code_source_map = CodeSourceMap::Handle( |
568 CodeSourceMap::Handle( | 586 zone, graph_compiler->code_source_map_builder()->Finalize()); |
569 zone, | |
570 graph_compiler->code_source_map_builder()->Finalize()); | |
571 code.set_code_source_map(code_source_map); | 587 code.set_code_source_map(code_source_map); |
572 if (FLAG_print_code_source_map) { | 588 if (FLAG_print_code_source_map) { |
573 CodeSourceMap::Dump(code_source_map, code, function); | 589 CodeSourceMap::Dump(code_source_map, code, function); |
574 } | 590 } |
575 ); | 591 #endif // !defined(PRODUCT) |
| 592 |
576 if (optimized()) { | 593 if (optimized()) { |
577 bool code_was_installed = false; | 594 bool code_was_installed = false; |
578 // Installs code while at safepoint. | 595 // Installs code while at safepoint. |
579 if (thread()->IsMutatorThread()) { | 596 if (thread()->IsMutatorThread()) { |
580 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; | 597 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; |
581 function.InstallOptimizedCode(code, is_osr); | 598 function.InstallOptimizedCode(code, is_osr); |
582 code_was_installed = true; | 599 code_was_installed = true; |
583 } else { | 600 } else { |
584 // Background compilation. | 601 // Background compilation. |
585 // Before installing code check generation counts if the code may | 602 // Before installing code check generation counts if the code may |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 (*prefixes)[i]->RegisterDependentCode(code); | 685 (*prefixes)[i]->RegisterDependentCode(code); |
669 } | 686 } |
670 } | 687 } |
671 } | 688 } |
672 | 689 |
673 | 690 |
674 void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped() { | 691 void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped() { |
675 ASSERT(Compiler::IsBackgroundCompilation()); | 692 ASSERT(Compiler::IsBackgroundCompilation()); |
676 if (!isolate()->background_compiler()->is_running()) { | 693 if (!isolate()->background_compiler()->is_running()) { |
677 // The background compiler is being stopped. | 694 // The background compiler is being stopped. |
678 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId, | 695 Compiler::AbortBackgroundCompilation( |
679 "Background compilation is being stopped"); | 696 Thread::kNoDeoptId, "Background compilation is being stopped"); |
680 } | 697 } |
681 } | 698 } |
682 | 699 |
683 | 700 |
684 // Return false if bailed out. | 701 // Return false if bailed out. |
685 // If optimized_result_code is not NULL then it is caller's responsibility | 702 // If optimized_result_code is not NULL then it is caller's responsibility |
686 // to install code. | 703 // to install code. |
687 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { | 704 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
688 ASSERT(!FLAG_precompiled_mode); | 705 ASSERT(!FLAG_precompiled_mode); |
689 const Function& function = parsed_function()->function(); | 706 const Function& function = parsed_function()->function(); |
690 if (optimized() && !function.IsOptimizable()) { | 707 if (optimized() && !function.IsOptimizable()) { |
691 return false; | 708 return false; |
692 } | 709 } |
693 bool is_compiled = false; | 710 bool is_compiled = false; |
694 Zone* const zone = thread()->zone(); | 711 Zone* const zone = thread()->zone(); |
695 NOT_IN_PRODUCT( | 712 NOT_IN_PRODUCT(TimelineStream* compiler_timeline = |
696 TimelineStream* compiler_timeline = Timeline::GetCompilerStream()); | 713 Timeline::GetCompilerStream()); |
697 CSTAT_TIMER_SCOPE(thread(), codegen_timer); | 714 CSTAT_TIMER_SCOPE(thread(), codegen_timer); |
698 HANDLESCOPE(thread()); | 715 HANDLESCOPE(thread()); |
699 | 716 |
700 // We may reattempt compilation if the function needs to be assembled using | 717 // We may reattempt compilation if the function needs to be assembled using |
701 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 718 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
702 // done is set to false, and use_far_branches is set to true if there is a | 719 // done is set to false, and use_far_branches is set to true if there is a |
703 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 720 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
704 // while loop, done is set to true. use_far_branches is always false on ia32 | 721 // while loop, done is set to true. use_far_branches is always false on ia32 |
705 // and x64. | 722 // and x64. |
706 volatile bool done = false; | 723 volatile bool done = false; |
(...skipping 11 matching lines...) Expand all Loading... |
718 | 735 |
719 // Class hierarchy analysis is registered with the thread in the | 736 // Class hierarchy analysis is registered with the thread in the |
720 // constructor and unregisters itself upon destruction. | 737 // constructor and unregisters itself upon destruction. |
721 CHA cha(thread()); | 738 CHA cha(thread()); |
722 | 739 |
723 // TimerScope needs an isolate to be properly terminated in case of a | 740 // TimerScope needs an isolate to be properly terminated in case of a |
724 // LongJump. | 741 // LongJump. |
725 { | 742 { |
726 CSTAT_TIMER_SCOPE(thread(), graphbuilder_timer); | 743 CSTAT_TIMER_SCOPE(thread(), graphbuilder_timer); |
727 ZoneGrowableArray<const ICData*>* ic_data_array = | 744 ZoneGrowableArray<const ICData*>* ic_data_array = |
728 new(zone) ZoneGrowableArray<const ICData*>(); | 745 new (zone) ZoneGrowableArray<const ICData*>(); |
729 if (optimized()) { | 746 if (optimized()) { |
730 // Extract type feedback before the graph is built, as the graph | 747 // Extract type feedback before the graph is built, as the graph |
731 // builder uses it to attach it to nodes. | 748 // builder uses it to attach it to nodes. |
732 | 749 |
733 // In background compilation the deoptimization counter may have | 750 // In background compilation the deoptimization counter may have |
734 // already reached the limit. | 751 // already reached the limit. |
735 ASSERT(Compiler::IsBackgroundCompilation() || | 752 ASSERT(Compiler::IsBackgroundCompilation() || |
736 (function.deoptimization_counter() < | 753 (function.deoptimization_counter() < |
737 FLAG_max_deoptimization_counter_threshold)); | 754 FLAG_max_deoptimization_counter_threshold)); |
738 | 755 |
739 // 'Freeze' ICData in background compilation so that it does not | 756 // 'Freeze' ICData in background compilation so that it does not |
740 // change while compiling. | 757 // change while compiling. |
741 const bool clone_ic_data = Compiler::IsBackgroundCompilation(); | 758 const bool clone_ic_data = Compiler::IsBackgroundCompilation(); |
742 function.RestoreICDataMap(ic_data_array, clone_ic_data); | 759 function.RestoreICDataMap(ic_data_array, clone_ic_data); |
743 | 760 |
744 if (Compiler::IsBackgroundCompilation() && | 761 if (Compiler::IsBackgroundCompilation() && |
745 (function.ic_data_array() == Array::null())) { | 762 (function.ic_data_array() == Array::null())) { |
746 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId, | 763 Compiler::AbortBackgroundCompilation( |
747 "RestoreICDataMap: ICData array cleared."); | 764 Thread::kNoDeoptId, "RestoreICDataMap: ICData array cleared."); |
748 } | 765 } |
749 if (FLAG_print_ic_data_map) { | 766 if (FLAG_print_ic_data_map) { |
750 for (intptr_t i = 0; i < ic_data_array->length(); i++) { | 767 for (intptr_t i = 0; i < ic_data_array->length(); i++) { |
751 if ((*ic_data_array)[i] != NULL) { | 768 if ((*ic_data_array)[i] != NULL) { |
752 THR_Print("%" Pd " ", i); | 769 THR_Print("%" Pd " ", i); |
753 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); | 770 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); |
754 } | 771 } |
755 } | 772 } |
756 } | 773 } |
757 } | 774 } |
758 | 775 |
759 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), | 776 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
760 compiler_timeline, | 777 "BuildFlowGraph")); |
761 "BuildFlowGraph");) | 778 flow_graph = pipeline->BuildFlowGraph(zone, parsed_function(), |
762 flow_graph = pipeline->BuildFlowGraph(zone, | 779 *ic_data_array, osr_id()); |
763 parsed_function(), | |
764 *ic_data_array, | |
765 osr_id()); | |
766 } | 780 } |
767 | 781 |
768 const bool print_flow_graph = | 782 const bool print_flow_graph = |
769 (FLAG_print_flow_graph || | 783 (FLAG_print_flow_graph || |
770 (optimized() && FLAG_print_flow_graph_optimized)) && | 784 (optimized() && FLAG_print_flow_graph_optimized)) && |
771 FlowGraphPrinter::ShouldPrint(function); | 785 FlowGraphPrinter::ShouldPrint(function); |
772 | 786 |
773 if (print_flow_graph) { | 787 if (print_flow_graph) { |
774 if (osr_id() == Compiler::kNoOSRDeoptId) { | 788 if (osr_id() == Compiler::kNoOSRDeoptId) { |
775 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); | 789 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); |
776 } else { | 790 } else { |
777 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); | 791 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); |
778 } | 792 } |
779 } | 793 } |
780 | 794 |
781 BlockScheduler block_scheduler(flow_graph); | 795 BlockScheduler block_scheduler(flow_graph); |
782 const bool reorder_blocks = | 796 const bool reorder_blocks = |
783 FlowGraph::ShouldReorderBlocks(function, optimized()); | 797 FlowGraph::ShouldReorderBlocks(function, optimized()); |
784 if (reorder_blocks) { | 798 if (reorder_blocks) { |
785 NOT_IN_PRODUCT(TimelineDurationScope tds( | 799 NOT_IN_PRODUCT(TimelineDurationScope tds( |
786 thread(), compiler_timeline, "BlockScheduler::AssignEdgeWeights")); | 800 thread(), compiler_timeline, "BlockScheduler::AssignEdgeWeights")); |
787 block_scheduler.AssignEdgeWeights(); | 801 block_scheduler.AssignEdgeWeights(); |
788 } | 802 } |
789 | 803 |
790 if (optimized()) { | 804 if (optimized()) { |
791 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), | 805 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
792 compiler_timeline, | |
793 "ComputeSSA")); | 806 "ComputeSSA")); |
794 CSTAT_TIMER_SCOPE(thread(), ssa_timer); | 807 CSTAT_TIMER_SCOPE(thread(), ssa_timer); |
795 // Transform to SSA (virtual register 0 and no inlining arguments). | 808 // Transform to SSA (virtual register 0 and no inlining arguments). |
796 flow_graph->ComputeSSA(0, NULL); | 809 flow_graph->ComputeSSA(0, NULL); |
797 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 810 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
798 if (print_flow_graph) { | 811 if (print_flow_graph) { |
799 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); | 812 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); |
800 } | 813 } |
801 } | 814 } |
802 | 815 |
803 // Maps inline_id_to_function[inline_id] -> function. Top scope | 816 // Maps inline_id_to_function[inline_id] -> function. Top scope |
804 // function has inline_id 0. The map is populated by the inliner. | 817 // function has inline_id 0. The map is populated by the inliner. |
805 GrowableArray<const Function*> inline_id_to_function; | 818 GrowableArray<const Function*> inline_id_to_function; |
806 // Token position where inlining occured. | 819 // Token position where inlining occured. |
807 GrowableArray<TokenPosition> inline_id_to_token_pos; | 820 GrowableArray<TokenPosition> inline_id_to_token_pos; |
808 // For a given inlining-id(index) specifies the caller's inlining-id. | 821 // For a given inlining-id(index) specifies the caller's inlining-id. |
809 GrowableArray<intptr_t> caller_inline_id; | 822 GrowableArray<intptr_t> caller_inline_id; |
810 // Collect all instance fields that are loaded in the graph and | 823 // Collect all instance fields that are loaded in the graph and |
811 // have non-generic type feedback attached to them that can | 824 // have non-generic type feedback attached to them that can |
812 // potentially affect optimizations. | 825 // potentially affect optimizations. |
813 if (optimized()) { | 826 if (optimized()) { |
814 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), | 827 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
815 compiler_timeline, | |
816 "OptimizationPasses")); | 828 "OptimizationPasses")); |
817 inline_id_to_function.Add(&function); | 829 inline_id_to_function.Add(&function); |
818 // We do not add the token position now because we don't know the | 830 // We do not add the token position now because we don't know the |
819 // position of the inlined call until later. A side effect of this | 831 // position of the inlined call until later. A side effect of this |
820 // is that the length of |inline_id_to_function| is always larger | 832 // is that the length of |inline_id_to_function| is always larger |
821 // than the length of |inline_id_to_token_pos| by one. | 833 // than the length of |inline_id_to_token_pos| by one. |
822 // Top scope function has no caller (-1). We do this because we expect | 834 // Top scope function has no caller (-1). We do this because we expect |
823 // all token positions to be at an inlined call. | 835 // all token positions to be at an inlined call. |
824 caller_inline_id.Add(-1); | 836 caller_inline_id.Add(-1); |
825 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); | 837 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); |
826 | 838 |
827 JitOptimizer optimizer(flow_graph); | 839 JitOptimizer optimizer(flow_graph); |
828 | 840 |
829 optimizer.ApplyICData(); | 841 optimizer.ApplyICData(); |
830 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 842 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
831 | 843 |
832 // Optimize (a << b) & c patterns, merge operations. | 844 // Optimize (a << b) & c patterns, merge operations. |
833 // Run early in order to have more opportunity to optimize left shifts. | 845 // Run early in order to have more opportunity to optimize left shifts. |
834 flow_graph->TryOptimizePatterns(); | 846 flow_graph->TryOptimizePatterns(); |
835 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 847 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
836 | 848 |
837 FlowGraphInliner::SetInliningId(flow_graph, 0); | 849 FlowGraphInliner::SetInliningId(flow_graph, 0); |
838 | 850 |
839 // Inlining (mutates the flow graph) | 851 // Inlining (mutates the flow graph) |
840 if (FLAG_use_inlining) { | 852 if (FLAG_use_inlining) { |
841 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 853 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
842 compiler_timeline, | |
843 "Inlining")); | 854 "Inlining")); |
844 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); | 855 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); |
845 // Propagate types to create more inlining opportunities. | 856 // Propagate types to create more inlining opportunities. |
846 FlowGraphTypePropagator::Propagate(flow_graph); | 857 FlowGraphTypePropagator::Propagate(flow_graph); |
847 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 858 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
848 | 859 |
849 // Use propagated class-ids to create more inlining opportunities. | 860 // Use propagated class-ids to create more inlining opportunities. |
850 optimizer.ApplyClassIds(); | 861 optimizer.ApplyClassIds(); |
851 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 862 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
852 | 863 |
853 FlowGraphInliner inliner(flow_graph, | 864 FlowGraphInliner inliner(flow_graph, &inline_id_to_function, |
854 &inline_id_to_function, | 865 &inline_id_to_token_pos, &caller_inline_id, |
855 &inline_id_to_token_pos, | |
856 &caller_inline_id, | |
857 use_speculative_inlining, | 866 use_speculative_inlining, |
858 /*inlining_black_list=*/ NULL, | 867 /*inlining_black_list=*/NULL, |
859 /*precompiler=*/ NULL); | 868 /*precompiler=*/NULL); |
860 inliner.Inline(); | 869 inliner.Inline(); |
861 // Use lists are maintained and validated by the inliner. | 870 // Use lists are maintained and validated by the inliner. |
862 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 871 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
863 } | 872 } |
864 | 873 |
865 // Propagate types and eliminate more type tests. | 874 // Propagate types and eliminate more type tests. |
866 FlowGraphTypePropagator::Propagate(flow_graph); | 875 FlowGraphTypePropagator::Propagate(flow_graph); |
867 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 876 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
868 | 877 |
869 { | 878 { |
870 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 879 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
871 compiler_timeline, | |
872 "ApplyClassIds")); | 880 "ApplyClassIds")); |
873 // Use propagated class-ids to optimize further. | 881 // Use propagated class-ids to optimize further. |
874 optimizer.ApplyClassIds(); | 882 optimizer.ApplyClassIds(); |
875 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 883 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
876 } | 884 } |
877 | 885 |
878 // Propagate types for potentially newly added instructions by | 886 // Propagate types for potentially newly added instructions by |
879 // ApplyClassIds(). Must occur before canonicalization. | 887 // ApplyClassIds(). Must occur before canonicalization. |
880 FlowGraphTypePropagator::Propagate(flow_graph); | 888 FlowGraphTypePropagator::Propagate(flow_graph); |
881 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 889 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
882 | 890 |
883 // Do optimizations that depend on the propagated type information. | 891 // Do optimizations that depend on the propagated type information. |
884 if (flow_graph->Canonicalize()) { | 892 if (flow_graph->Canonicalize()) { |
885 // Invoke Canonicalize twice in order to fully canonicalize patterns | 893 // Invoke Canonicalize twice in order to fully canonicalize patterns |
886 // like "if (a & const == 0) { }". | 894 // like "if (a & const == 0) { }". |
887 flow_graph->Canonicalize(); | 895 flow_graph->Canonicalize(); |
888 } | 896 } |
889 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 897 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
890 | 898 |
891 { | 899 { |
892 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 900 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
893 compiler_timeline, | |
894 "BranchSimplifier")); | 901 "BranchSimplifier")); |
895 BranchSimplifier::Simplify(flow_graph); | 902 BranchSimplifier::Simplify(flow_graph); |
896 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 903 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
897 | 904 |
898 IfConverter::Simplify(flow_graph); | 905 IfConverter::Simplify(flow_graph); |
899 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 906 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
900 } | 907 } |
901 | 908 |
902 if (FLAG_constant_propagation) { | 909 if (FLAG_constant_propagation) { |
903 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 910 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
904 compiler_timeline, | |
905 "ConstantPropagation"); | 911 "ConstantPropagation"); |
906 ConstantPropagator::Optimize(flow_graph)); | 912 ConstantPropagator::Optimize(flow_graph)); |
907 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 913 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
908 // A canonicalization pass to remove e.g. smi checks on smi constants. | 914 // A canonicalization pass to remove e.g. smi checks on smi constants. |
909 flow_graph->Canonicalize(); | 915 flow_graph->Canonicalize(); |
910 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 916 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
911 // Canonicalization introduced more opportunities for constant | 917 // Canonicalization introduced more opportunities for constant |
912 // propagation. | 918 // propagation. |
913 ConstantPropagator::Optimize(flow_graph); | 919 ConstantPropagator::Optimize(flow_graph); |
914 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 920 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
915 } | 921 } |
916 | 922 |
917 // Optimistically convert loop phis that have a single non-smi input | 923 // Optimistically convert loop phis that have a single non-smi input |
918 // coming from the loop pre-header into smi-phis. | 924 // coming from the loop pre-header into smi-phis. |
919 if (FLAG_loop_invariant_code_motion) { | 925 if (FLAG_loop_invariant_code_motion) { |
920 LICM licm(flow_graph); | 926 LICM licm(flow_graph); |
921 licm.OptimisticallySpecializeSmiPhis(); | 927 licm.OptimisticallySpecializeSmiPhis(); |
922 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 928 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
923 } | 929 } |
924 | 930 |
925 // Propagate types and eliminate even more type tests. | 931 // Propagate types and eliminate even more type tests. |
926 // Recompute types after constant propagation to infer more precise | 932 // Recompute types after constant propagation to infer more precise |
927 // types for uses that were previously reached by now eliminated phis. | 933 // types for uses that were previously reached by now eliminated phis. |
928 FlowGraphTypePropagator::Propagate(flow_graph); | 934 FlowGraphTypePropagator::Propagate(flow_graph); |
929 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 935 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
930 | 936 |
931 { | 937 { |
932 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 938 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
933 compiler_timeline, | |
934 "SelectRepresentations")); | 939 "SelectRepresentations")); |
935 // Where beneficial convert Smi operations into Int32 operations. | 940 // Where beneficial convert Smi operations into Int32 operations. |
936 // Only meanigful for 32bit platforms right now. | 941 // Only meanigful for 32bit platforms right now. |
937 flow_graph->WidenSmiToInt32(); | 942 flow_graph->WidenSmiToInt32(); |
938 | 943 |
939 // Unbox doubles. Performed after constant propagation to minimize | 944 // Unbox doubles. Performed after constant propagation to minimize |
940 // interference from phis merging double values and tagged | 945 // interference from phis merging double values and tagged |
941 // values coming from dead paths. | 946 // values coming from dead paths. |
942 flow_graph->SelectRepresentations(); | 947 flow_graph->SelectRepresentations(); |
943 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 948 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
976 flow_graph->RemoveRedefinitions(); | 981 flow_graph->RemoveRedefinitions(); |
977 } | 982 } |
978 | 983 |
979 // Optimize (a << b) & c patterns, merge operations. | 984 // Optimize (a << b) & c patterns, merge operations. |
980 // Run after CSE in order to have more opportunity to merge | 985 // Run after CSE in order to have more opportunity to merge |
981 // instructions that have same inputs. | 986 // instructions that have same inputs. |
982 flow_graph->TryOptimizePatterns(); | 987 flow_graph->TryOptimizePatterns(); |
983 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 988 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
984 | 989 |
985 { | 990 { |
986 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 991 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
987 compiler_timeline, | |
988 "DeadStoreElimination")); | 992 "DeadStoreElimination")); |
989 DeadStoreElimination::Optimize(flow_graph); | 993 DeadStoreElimination::Optimize(flow_graph); |
990 } | 994 } |
991 | 995 |
992 if (FLAG_range_analysis) { | 996 if (FLAG_range_analysis) { |
993 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 997 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
994 compiler_timeline, | |
995 "RangeAnalysis")); | 998 "RangeAnalysis")); |
996 // Propagate types after store-load-forwarding. Some phis may have | 999 // Propagate types after store-load-forwarding. Some phis may have |
997 // become smi phis that can be processed by range analysis. | 1000 // become smi phis that can be processed by range analysis. |
998 FlowGraphTypePropagator::Propagate(flow_graph); | 1001 FlowGraphTypePropagator::Propagate(flow_graph); |
999 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1002 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
1000 | 1003 |
1001 // We have to perform range analysis after LICM because it | 1004 // We have to perform range analysis after LICM because it |
1002 // optimistically moves CheckSmi through phis into loop preheaders | 1005 // optimistically moves CheckSmi through phis into loop preheaders |
1003 // making some phis smi. | 1006 // making some phis smi. |
1004 RangeAnalysis range_analysis(flow_graph); | 1007 RangeAnalysis range_analysis(flow_graph); |
(...skipping 23 matching lines...) Expand all Loading... |
1028 // Optimize try-blocks. | 1031 // Optimize try-blocks. |
1029 TryCatchAnalyzer::Optimize(flow_graph); | 1032 TryCatchAnalyzer::Optimize(flow_graph); |
1030 } | 1033 } |
1031 | 1034 |
1032 // Detach environments from the instructions that can't deoptimize. | 1035 // Detach environments from the instructions that can't deoptimize. |
1033 // Do it before we attempt to perform allocation sinking to minimize | 1036 // Do it before we attempt to perform allocation sinking to minimize |
1034 // amount of materializations it has to perform. | 1037 // amount of materializations it has to perform. |
1035 flow_graph->EliminateEnvironments(); | 1038 flow_graph->EliminateEnvironments(); |
1036 | 1039 |
1037 { | 1040 { |
1038 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 1041 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
1039 compiler_timeline, | |
1040 "EliminateDeadPhis")); | 1042 "EliminateDeadPhis")); |
1041 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 1043 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
1042 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1044 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
1043 } | 1045 } |
1044 | 1046 |
1045 if (flow_graph->Canonicalize()) { | 1047 if (flow_graph->Canonicalize()) { |
1046 flow_graph->Canonicalize(); | 1048 flow_graph->Canonicalize(); |
1047 } | 1049 } |
1048 | 1050 |
1049 // Attempt to sink allocations of temporary non-escaping objects to | 1051 // Attempt to sink allocations of temporary non-escaping objects to |
1050 // the deoptimization path. | 1052 // the deoptimization path. |
1051 AllocationSinking* sinking = NULL; | 1053 AllocationSinking* sinking = NULL; |
1052 if (FLAG_allocation_sinking && | 1054 if (FLAG_allocation_sinking && |
1053 (flow_graph->graph_entry()->SuccessorCount() == 1)) { | 1055 (flow_graph->graph_entry()->SuccessorCount() == 1)) { |
1054 NOT_IN_PRODUCT(TimelineDurationScope tds2( | 1056 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
1055 thread(), compiler_timeline, "AllocationSinking::Optimize")); | 1057 thread(), compiler_timeline, "AllocationSinking::Optimize")); |
1056 // TODO(fschneider): Support allocation sinking with try-catch. | 1058 // TODO(fschneider): Support allocation sinking with try-catch. |
1057 sinking = new AllocationSinking(flow_graph); | 1059 sinking = new AllocationSinking(flow_graph); |
1058 sinking->Optimize(); | 1060 sinking->Optimize(); |
1059 } | 1061 } |
1060 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1062 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
1061 | 1063 |
1062 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 1064 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
1063 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1065 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
1064 | 1066 |
1065 FlowGraphTypePropagator::Propagate(flow_graph); | 1067 FlowGraphTypePropagator::Propagate(flow_graph); |
1066 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1068 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
1067 | 1069 |
1068 { | 1070 { |
1069 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 1071 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
1070 compiler_timeline, | |
1071 "SelectRepresentations")); | 1072 "SelectRepresentations")); |
1072 // Ensure that all phis inserted by optimization passes have | 1073 // Ensure that all phis inserted by optimization passes have |
1073 // consistent representations. | 1074 // consistent representations. |
1074 flow_graph->SelectRepresentations(); | 1075 flow_graph->SelectRepresentations(); |
1075 } | 1076 } |
1076 | 1077 |
1077 if (flow_graph->Canonicalize()) { | 1078 if (flow_graph->Canonicalize()) { |
1078 // To fully remove redundant boxing (e.g. BoxDouble used only in | 1079 // To fully remove redundant boxing (e.g. BoxDouble used only in |
1079 // environments and UnboxDouble instructions) instruction we | 1080 // environments and UnboxDouble instructions) instruction we |
1080 // first need to replace all their uses and then fold them away. | 1081 // first need to replace all their uses and then fold them away. |
(...skipping 12 matching lines...) Expand all Loading... |
1093 // referenced only from environments. Register allocator will consider | 1094 // referenced only from environments. Register allocator will consider |
1094 // them as part of a deoptimization environment. | 1095 // them as part of a deoptimization environment. |
1095 sinking->DetachMaterializations(); | 1096 sinking->DetachMaterializations(); |
1096 } | 1097 } |
1097 | 1098 |
1098 // Compute and store graph informations (call & instruction counts) | 1099 // Compute and store graph informations (call & instruction counts) |
1099 // to be later used by the inliner. | 1100 // to be later used by the inliner. |
1100 FlowGraphInliner::CollectGraphInfo(flow_graph, true); | 1101 FlowGraphInliner::CollectGraphInfo(flow_graph, true); |
1101 | 1102 |
1102 { | 1103 { |
1103 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), | 1104 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), compiler_timeline, |
1104 compiler_timeline, | |
1105 "AllocateRegisters")); | 1105 "AllocateRegisters")); |
1106 // Perform register allocation on the SSA graph. | 1106 // Perform register allocation on the SSA graph. |
1107 FlowGraphAllocator allocator(*flow_graph); | 1107 FlowGraphAllocator allocator(*flow_graph); |
1108 allocator.AllocateRegisters(); | 1108 allocator.AllocateRegisters(); |
1109 } | 1109 } |
1110 | 1110 |
1111 if (reorder_blocks) { | 1111 if (reorder_blocks) { |
1112 NOT_IN_PRODUCT(TimelineDurationScope tds( | 1112 NOT_IN_PRODUCT(TimelineDurationScope tds( |
1113 thread(), compiler_timeline, "BlockScheduler::ReorderBlocks")); | 1113 thread(), compiler_timeline, "BlockScheduler::ReorderBlocks")); |
1114 block_scheduler.ReorderBlocks(); | 1114 block_scheduler.ReorderBlocks(); |
1115 } | 1115 } |
1116 | 1116 |
1117 if (print_flow_graph) { | 1117 if (print_flow_graph) { |
1118 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); | 1118 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); |
1119 } | 1119 } |
1120 } | 1120 } |
1121 | 1121 |
1122 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); | 1122 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); |
1123 Assembler assembler(use_far_branches); | 1123 Assembler assembler(use_far_branches); |
1124 FlowGraphCompiler graph_compiler(&assembler, flow_graph, | 1124 FlowGraphCompiler graph_compiler( |
1125 *parsed_function(), optimized(), | 1125 &assembler, flow_graph, *parsed_function(), optimized(), |
1126 inline_id_to_function, | 1126 inline_id_to_function, inline_id_to_token_pos, caller_inline_id); |
1127 inline_id_to_token_pos, | |
1128 caller_inline_id); | |
1129 { | 1127 { |
1130 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); | 1128 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); |
1131 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), | 1129 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
1132 compiler_timeline, | |
1133 "CompileGraph")); | 1130 "CompileGraph")); |
1134 graph_compiler.CompileGraph(); | 1131 graph_compiler.CompileGraph(); |
1135 pipeline->FinalizeCompilation(flow_graph); | 1132 pipeline->FinalizeCompilation(flow_graph); |
1136 } | 1133 } |
1137 { | 1134 { |
1138 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), | 1135 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
1139 compiler_timeline, | |
1140 "FinalizeCompilation")); | 1136 "FinalizeCompilation")); |
1141 if (thread()->IsMutatorThread()) { | 1137 if (thread()->IsMutatorThread()) { |
1142 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | 1138 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); |
1143 } else { | 1139 } else { |
1144 // This part of compilation must be at a safepoint. | 1140 // This part of compilation must be at a safepoint. |
1145 // Stop mutator thread before creating the instruction object and | 1141 // Stop mutator thread before creating the instruction object and |
1146 // installing code. | 1142 // installing code. |
1147 // Mutator thread may not run code while we are creating the | 1143 // Mutator thread may not run code while we are creating the |
1148 // instruction object, since the creation of instruction object | 1144 // instruction object, since the creation of instruction object |
1149 // changes code page access permissions (makes them temporary not | 1145 // changes code page access permissions (makes them temporary not |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1202 } | 1198 } |
1203 is_compiled = false; | 1199 is_compiled = false; |
1204 } | 1200 } |
1205 // Reset global isolate state. | 1201 // Reset global isolate state. |
1206 thread()->set_deopt_id(prev_deopt_id); | 1202 thread()->set_deopt_id(prev_deopt_id); |
1207 } | 1203 } |
1208 return is_compiled; | 1204 return is_compiled; |
1209 } | 1205 } |
1210 | 1206 |
1211 | 1207 |
1212 DEBUG_ONLY( | 1208 #if defined(DEBUG) |
1213 // Verifies that the inliner is always in the list of inlined functions. | 1209 // Verifies that the inliner is always in the list of inlined functions. |
1214 // If this fails run with --trace-inlining-intervals to get more information. | 1210 // If this fails run with --trace-inlining-intervals to get more information. |
1215 static void CheckInliningIntervals(const Function& function) { | 1211 static void CheckInliningIntervals(const Function& function) { |
1216 const Code& code = Code::Handle(function.CurrentCode()); | 1212 const Code& code = Code::Handle(function.CurrentCode()); |
1217 const Array& intervals = Array::Handle(code.GetInlinedIntervals()); | 1213 const Array& intervals = Array::Handle(code.GetInlinedIntervals()); |
1218 if (intervals.IsNull() || (intervals.Length() == 0)) return; | 1214 if (intervals.IsNull() || (intervals.Length() == 0)) return; |
1219 Smi& start = Smi::Handle(); | 1215 Smi& start = Smi::Handle(); |
1220 GrowableArray<Function*> inlined_functions; | 1216 GrowableArray<Function*> inlined_functions; |
1221 for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) { | 1217 for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) { |
1222 start ^= intervals.At(i + Code::kInlIntStart); | 1218 start ^= intervals.At(i + Code::kInlIntStart); |
1223 ASSERT(!start.IsNull()); | 1219 ASSERT(!start.IsNull()); |
1224 if (start.IsNull()) continue; | 1220 if (start.IsNull()) continue; |
1225 code.GetInlinedFunctionsAt(start.Value(), &inlined_functions); | 1221 code.GetInlinedFunctionsAt(start.Value(), &inlined_functions); |
1226 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == | 1222 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == |
1227 function.raw()); | 1223 function.raw()); |
1228 } | 1224 } |
1229 } | 1225 } |
1230 ) | 1226 #endif // defined(DEBUG) |
1231 | 1227 |
1232 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1228 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
1233 const Function& function, | 1229 const Function& function, |
1234 bool optimized, | 1230 bool optimized, |
1235 intptr_t osr_id) { | 1231 intptr_t osr_id) { |
1236 ASSERT(!FLAG_precompiled_mode); | 1232 ASSERT(!FLAG_precompiled_mode); |
1237 ASSERT(!optimized || function.was_compiled()); | 1233 ASSERT(!optimized || function.was_compiled()); |
1238 LongJumpScope jump; | 1234 LongJumpScope jump; |
1239 if (setjmp(*jump.Set()) == 0) { | 1235 if (setjmp(*jump.Set()) == 0) { |
1240 Thread* const thread = Thread::Current(); | 1236 Thread* const thread = Thread::Current(); |
1241 Isolate* const isolate = thread->isolate(); | 1237 Isolate* const isolate = thread->isolate(); |
1242 StackZone stack_zone(thread); | 1238 StackZone stack_zone(thread); |
1243 Zone* const zone = stack_zone.GetZone(); | 1239 Zone* const zone = stack_zone.GetZone(); |
1244 const bool trace_compiler = | 1240 const bool trace_compiler = |
1245 FLAG_trace_compiler || | 1241 FLAG_trace_compiler || (FLAG_trace_optimizing_compiler && optimized); |
1246 (FLAG_trace_optimizing_compiler && optimized); | |
1247 Timer per_compile_timer(trace_compiler, "Compilation time"); | 1242 Timer per_compile_timer(trace_compiler, "Compilation time"); |
1248 per_compile_timer.Start(); | 1243 per_compile_timer.Start(); |
1249 | 1244 |
1250 ParsedFunction* parsed_function = new(zone) ParsedFunction( | 1245 ParsedFunction* parsed_function = new (zone) |
1251 thread, Function::ZoneHandle(zone, function.raw())); | 1246 ParsedFunction(thread, Function::ZoneHandle(zone, function.raw())); |
1252 if (trace_compiler) { | 1247 if (trace_compiler) { |
1253 const intptr_t token_size = function.end_token_pos().Pos() - | 1248 const intptr_t token_size = |
1254 function.token_pos().Pos(); | 1249 function.end_token_pos().Pos() - function.token_pos().Pos(); |
1255 THR_Print("Compiling %s%sfunction %s: '%s' @ token %s, size %" Pd "\n", | 1250 THR_Print("Compiling %s%sfunction %s: '%s' @ token %s, size %" Pd "\n", |
1256 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), | 1251 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), |
1257 (optimized ? "optimized " : ""), | 1252 (optimized ? "optimized " : ""), |
1258 (Compiler::IsBackgroundCompilation() ? "(background)" : ""), | 1253 (Compiler::IsBackgroundCompilation() ? "(background)" : ""), |
1259 function.ToFullyQualifiedCString(), | 1254 function.ToFullyQualifiedCString(), |
1260 function.token_pos().ToCString(), | 1255 function.token_pos().ToCString(), token_size); |
1261 token_size); | |
1262 } | 1256 } |
1263 INC_STAT(thread, num_functions_compiled, 1); | 1257 INC_STAT(thread, num_functions_compiled, 1); |
1264 if (optimized) { | 1258 if (optimized) { |
1265 INC_STAT(thread, num_functions_optimized, 1); | 1259 INC_STAT(thread, num_functions_optimized, 1); |
1266 } | 1260 } |
1267 // Makes sure no classes are loaded during parsing in background. | 1261 // Makes sure no classes are loaded during parsing in background. |
1268 const intptr_t loading_invalidation_gen_at_start = | 1262 const intptr_t loading_invalidation_gen_at_start = |
1269 isolate->loading_invalidation_gen(); | 1263 isolate->loading_invalidation_gen(); |
1270 { | 1264 { |
1271 HANDLESCOPE(thread); | 1265 HANDLESCOPE(thread); |
1272 const int64_t num_tokens_before = STAT_VALUE(thread, num_tokens_consumed); | 1266 const int64_t num_tokens_before = STAT_VALUE(thread, num_tokens_consumed); |
1273 pipeline->ParseFunction(parsed_function); | 1267 pipeline->ParseFunction(parsed_function); |
1274 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); | 1268 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); |
1275 INC_STAT(thread, | 1269 INC_STAT(thread, num_func_tokens_compiled, |
1276 num_func_tokens_compiled, | |
1277 num_tokens_after - num_tokens_before); | 1270 num_tokens_after - num_tokens_before); |
1278 } | 1271 } |
1279 | 1272 |
1280 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); | 1273 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); |
1281 | 1274 |
1282 if (Compiler::IsBackgroundCompilation()) { | 1275 if (Compiler::IsBackgroundCompilation()) { |
1283 if (isolate->IsTopLevelParsing() || | 1276 if (isolate->IsTopLevelParsing() || |
1284 (loading_invalidation_gen_at_start != | 1277 (loading_invalidation_gen_at_start != |
1285 isolate->loading_invalidation_gen())) { | 1278 isolate->loading_invalidation_gen())) { |
1286 // Loading occured while parsing. We need to abort here because state | 1279 // Loading occured while parsing. We need to abort here because state |
1287 // changed while compiling. | 1280 // changed while compiling. |
1288 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId, | 1281 Compiler::AbortBackgroundCompilation( |
| 1282 Thread::kNoDeoptId, |
1289 "Invalidated state during parsing because of script loading"); | 1283 "Invalidated state during parsing because of script loading"); |
1290 } | 1284 } |
1291 } | 1285 } |
1292 | 1286 |
1293 const bool success = helper.Compile(pipeline); | 1287 const bool success = helper.Compile(pipeline); |
1294 if (success) { | 1288 if (success) { |
1295 if (!optimized) { | 1289 if (!optimized) { |
1296 function.set_was_compiled(true); | 1290 function.set_was_compiled(true); |
1297 } | 1291 } |
1298 } else { | 1292 } else { |
1299 if (optimized) { | 1293 if (optimized) { |
1300 if (Compiler::IsBackgroundCompilation()) { | 1294 if (Compiler::IsBackgroundCompilation()) { |
1301 // Try again later, background compilation may abort because of | 1295 // Try again later, background compilation may abort because of |
1302 // state change during compilation. | 1296 // state change during compilation. |
1303 if (FLAG_trace_compiler) { | 1297 if (FLAG_trace_compiler) { |
1304 THR_Print("Aborted background compilation: %s\n", | 1298 THR_Print("Aborted background compilation: %s\n", |
1305 function.ToFullyQualifiedCString()); | 1299 function.ToFullyQualifiedCString()); |
1306 } | 1300 } |
1307 { | 1301 { |
1308 // If it was a bailout, then disable optimization. | 1302 // If it was a bailout, then disable optimization. |
1309 Error& error = Error::Handle(); | 1303 Error& error = Error::Handle(); |
1310 // We got an error during compilation. | 1304 // We got an error during compilation. |
1311 error = thread->sticky_error(); | 1305 error = thread->sticky_error(); |
1312 thread->clear_sticky_error(); | 1306 thread->clear_sticky_error(); |
1313 if ((error.IsLanguageError() && | 1307 if ((error.IsLanguageError() && |
1314 LanguageError::Cast(error).kind() == Report::kBailout) || | 1308 LanguageError::Cast(error).kind() == Report::kBailout) || |
1315 error.IsUnhandledException()) { | 1309 error.IsUnhandledException()) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1357 Code::Handle(function.CurrentCode()).Size(), | 1351 Code::Handle(function.CurrentCode()).Size(), |
1358 per_compile_timer.TotalElapsedTime()); | 1352 per_compile_timer.TotalElapsedTime()); |
1359 } | 1353 } |
1360 | 1354 |
1361 if (FLAG_support_debugger) { | 1355 if (FLAG_support_debugger) { |
1362 isolate->debugger()->NotifyCompilation(function); | 1356 isolate->debugger()->NotifyCompilation(function); |
1363 } | 1357 } |
1364 | 1358 |
1365 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { | 1359 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { |
1366 Disassembler::DisassembleCode(function, optimized); | 1360 Disassembler::DisassembleCode(function, optimized); |
1367 } else if (FLAG_disassemble_optimized && | 1361 } else if (FLAG_disassemble_optimized && optimized && |
1368 optimized && | |
1369 FlowGraphPrinter::ShouldPrint(function)) { | 1362 FlowGraphPrinter::ShouldPrint(function)) { |
1370 Disassembler::DisassembleCode(function, true); | 1363 Disassembler::DisassembleCode(function, true); |
1371 } | 1364 } |
1372 | 1365 |
1373 DEBUG_ONLY(CheckInliningIntervals(function)); | 1366 DEBUG_ONLY(CheckInliningIntervals(function)); |
1374 return Error::null(); | 1367 return Error::null(); |
1375 } else { | 1368 } else { |
1376 Thread* const thread = Thread::Current(); | 1369 Thread* const thread = Thread::Current(); |
1377 StackZone stack_zone(thread); | 1370 StackZone stack_zone(thread); |
1378 Error& error = Error::Handle(); | 1371 Error& error = Error::Handle(); |
1379 // We got an error during compilation or it is a bailout from background | 1372 // We got an error during compilation or it is a bailout from background |
1380 // compilation (e.g., during parsing with EnsureIsFinalized). | 1373 // compilation (e.g., during parsing with EnsureIsFinalized). |
1381 error = thread->sticky_error(); | 1374 error = thread->sticky_error(); |
1382 thread->clear_sticky_error(); | 1375 thread->clear_sticky_error(); |
1383 if (error.raw() == Object::background_compilation_error().raw()) { | 1376 if (error.raw() == Object::background_compilation_error().raw()) { |
1384 // Exit compilation, retry it later. | 1377 // Exit compilation, retry it later. |
1385 if (FLAG_trace_bailout) { | 1378 if (FLAG_trace_bailout) { |
1386 THR_Print("Aborted background compilation: %s\n", | 1379 THR_Print("Aborted background compilation: %s\n", |
1387 function.ToFullyQualifiedCString()); | 1380 function.ToFullyQualifiedCString()); |
1388 } | 1381 } |
1389 return Error::null(); | 1382 return Error::null(); |
1390 } | 1383 } |
1391 // Do not attempt to optimize functions that can cause errors. | 1384 // Do not attempt to optimize functions that can cause errors. |
1392 function.set_is_optimizable(false); | 1385 function.set_is_optimizable(false); |
1393 return error.raw(); | 1386 return error.raw(); |
1394 } | 1387 } |
1395 UNREACHABLE(); | 1388 UNREACHABLE(); |
1396 return Error::null(); | 1389 return Error::null(); |
1397 } | 1390 } |
1398 | 1391 |
1399 | 1392 |
1400 static RawError* ParseFunctionHelper(CompilationPipeline* pipeline, | 1393 static RawError* ParseFunctionHelper(CompilationPipeline* pipeline, |
1401 const Function& function, | 1394 const Function& function, |
1402 bool optimized, | 1395 bool optimized, |
1403 intptr_t osr_id) { | 1396 intptr_t osr_id) { |
1404 ASSERT(!FLAG_precompiled_mode); | 1397 ASSERT(!FLAG_precompiled_mode); |
1405 ASSERT(!optimized || function.was_compiled()); | 1398 ASSERT(!optimized || function.was_compiled()); |
1406 LongJumpScope jump; | 1399 LongJumpScope jump; |
1407 if (setjmp(*jump.Set()) == 0) { | 1400 if (setjmp(*jump.Set()) == 0) { |
1408 Thread* const thread = Thread::Current(); | 1401 Thread* const thread = Thread::Current(); |
1409 StackZone stack_zone(thread); | 1402 StackZone stack_zone(thread); |
1410 Zone* const zone = stack_zone.GetZone(); | 1403 Zone* const zone = stack_zone.GetZone(); |
1411 const bool trace_compiler = | 1404 const bool trace_compiler = |
1412 FLAG_trace_compiler || | 1405 FLAG_trace_compiler || (FLAG_trace_optimizing_compiler && optimized); |
1413 (FLAG_trace_optimizing_compiler && optimized); | |
1414 | 1406 |
1415 if (trace_compiler) { | 1407 if (trace_compiler) { |
1416 const intptr_t token_size = function.end_token_pos().Pos() - | 1408 const intptr_t token_size = |
1417 function.token_pos().Pos(); | 1409 function.end_token_pos().Pos() - function.token_pos().Pos(); |
1418 THR_Print("Parsing %s%sfunction %s: '%s' @ token %s, size %" Pd "\n", | 1410 THR_Print("Parsing %s%sfunction %s: '%s' @ token %s, size %" Pd "\n", |
1419 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), | 1411 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), |
1420 (optimized ? "optimized " : ""), | 1412 (optimized ? "optimized " : ""), |
1421 (Compiler::IsBackgroundCompilation() ? "(background)" : ""), | 1413 (Compiler::IsBackgroundCompilation() ? "(background)" : ""), |
1422 function.ToFullyQualifiedCString(), | 1414 function.ToFullyQualifiedCString(), |
1423 function.token_pos().ToCString(), | 1415 function.token_pos().ToCString(), token_size); |
1424 token_size); | |
1425 } | 1416 } |
1426 ParsedFunction* parsed_function = new(zone) ParsedFunction( | 1417 ParsedFunction* parsed_function = new (zone) |
1427 thread, Function::ZoneHandle(zone, function.raw())); | 1418 ParsedFunction(thread, Function::ZoneHandle(zone, function.raw())); |
1428 pipeline->ParseFunction(parsed_function); | 1419 pipeline->ParseFunction(parsed_function); |
1429 // For now we just walk thru the AST nodes and in DEBUG mode we print | 1420 // For now we just walk thru the AST nodes and in DEBUG mode we print |
1430 // them otherwise just skip through them, this will be need to be | 1421 // them otherwise just skip through them, this will be need to be |
1431 // wired to generate the IR format. | 1422 // wired to generate the IR format. |
1432 #if !defined(PRODUCT) | 1423 #if !defined(PRODUCT) |
1433 #if defined(DEBUG) | 1424 #if defined(DEBUG) |
1434 AstPrinter ast_printer(true); | 1425 AstPrinter ast_printer(true); |
1435 #else | 1426 #else |
1436 AstPrinter ast_printer(false); | 1427 AstPrinter ast_printer(false); |
1437 #endif // defined(DEBUG). | 1428 #endif // defined(DEBUG). |
1438 ast_printer.PrintFunctionNodes(*parsed_function); | 1429 ast_printer.PrintFunctionNodes(*parsed_function); |
1439 #endif // !defined(PRODUCT). | 1430 #endif // !defined(PRODUCT). |
1440 return Error::null(); | 1431 return Error::null(); |
1441 } else { | 1432 } else { |
1442 Thread* const thread = Thread::Current(); | 1433 Thread* const thread = Thread::Current(); |
1443 StackZone stack_zone(thread); | 1434 StackZone stack_zone(thread); |
1444 Error& error = Error::Handle(); | 1435 Error& error = Error::Handle(); |
1445 // We got an error during compilation or it is a bailout from background | 1436 // We got an error during compilation or it is a bailout from background |
1446 // compilation (e.g., during parsing with EnsureIsFinalized). | 1437 // compilation (e.g., during parsing with EnsureIsFinalized). |
1447 error = thread->sticky_error(); | 1438 error = thread->sticky_error(); |
1448 thread->clear_sticky_error(); | 1439 thread->clear_sticky_error(); |
1449 // Unoptimized compilation or precompilation may encounter compile-time | 1440 // Unoptimized compilation or precompilation may encounter compile-time |
1450 // errors, but regular optimized compilation should not. | 1441 // errors, but regular optimized compilation should not. |
1451 ASSERT(!optimized); | 1442 ASSERT(!optimized); |
1452 return error.raw(); | 1443 return error.raw(); |
1453 } | 1444 } |
1454 UNREACHABLE(); | 1445 UNREACHABLE(); |
1455 return Error::null(); | 1446 return Error::null(); |
1456 } | 1447 } |
1457 | 1448 |
1458 | 1449 |
1459 RawError* Compiler::CompileFunction(Thread* thread, | 1450 RawError* Compiler::CompileFunction(Thread* thread, const Function& function) { |
1460 const Function& function) { | |
1461 #ifdef DART_PRECOMPILER | 1451 #ifdef DART_PRECOMPILER |
1462 if (FLAG_precompiled_mode) { | 1452 if (FLAG_precompiled_mode) { |
1463 return Precompiler::CompileFunction( | 1453 return Precompiler::CompileFunction( |
1464 /* precompiler = */ NULL, thread, thread->zone(), function); | 1454 /* precompiler = */ NULL, thread, thread->zone(), function); |
1465 } | 1455 } |
1466 #endif | 1456 #endif |
| 1457 |
1467 Isolate* isolate = thread->isolate(); | 1458 Isolate* isolate = thread->isolate(); |
1468 NOT_IN_PRODUCT( | 1459 |
| 1460 #if !defined(PRODUCT) |
1469 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); | 1461 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
1470 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); | 1462 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); |
1471 ) // !PRODUCT | 1463 #endif // !defined(PRODUCT) |
1472 | 1464 |
1473 if (!isolate->compilation_allowed()) { | 1465 if (!isolate->compilation_allowed()) { |
1474 FATAL3("Precompilation missed function %s (%s, %s)\n", | 1466 FATAL3("Precompilation missed function %s (%s, %s)\n", |
1475 function.ToLibNamePrefixedQualifiedCString(), | 1467 function.ToLibNamePrefixedQualifiedCString(), |
1476 function.token_pos().ToCString(), | 1468 function.token_pos().ToCString(), |
1477 Function::KindToCString(function.kind())); | 1469 Function::KindToCString(function.kind())); |
1478 } | 1470 } |
1479 | 1471 |
1480 CompilationPipeline* pipeline = | 1472 CompilationPipeline* pipeline = |
1481 CompilationPipeline::New(thread->zone(), function); | 1473 CompilationPipeline::New(thread->zone(), function); |
1482 | 1474 |
1483 return CompileFunctionHelper(pipeline, | 1475 return CompileFunctionHelper(pipeline, function, |
1484 function, | 1476 /* optimized = */ false, kNoOSRDeoptId); |
1485 /* optimized = */ false, | |
1486 kNoOSRDeoptId); | |
1487 } | 1477 } |
1488 | 1478 |
1489 | 1479 |
1490 RawError* Compiler::ParseFunction(Thread* thread, | 1480 RawError* Compiler::ParseFunction(Thread* thread, const Function& function) { |
1491 const Function& function) { | |
1492 Isolate* isolate = thread->isolate(); | 1481 Isolate* isolate = thread->isolate(); |
1493 NOT_IN_PRODUCT( | 1482 #if !defined(PRODUCT) |
1494 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); | 1483 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
1495 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "ParseFunction", function); | 1484 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "ParseFunction", function); |
1496 ) // !PRODUCT | 1485 #endif // !defined(PRODUCT) |
1497 | 1486 |
1498 if (!isolate->compilation_allowed()) { | 1487 if (!isolate->compilation_allowed()) { |
1499 FATAL3("Precompilation missed function %s (%s, %s)\n", | 1488 FATAL3("Precompilation missed function %s (%s, %s)\n", |
1500 function.ToLibNamePrefixedQualifiedCString(), | 1489 function.ToLibNamePrefixedQualifiedCString(), |
1501 function.token_pos().ToCString(), | 1490 function.token_pos().ToCString(), |
1502 Function::KindToCString(function.kind())); | 1491 Function::KindToCString(function.kind())); |
1503 } | 1492 } |
1504 | 1493 |
1505 CompilationPipeline* pipeline = | 1494 CompilationPipeline* pipeline = |
1506 CompilationPipeline::New(thread->zone(), function); | 1495 CompilationPipeline::New(thread->zone(), function); |
1507 | 1496 |
1508 return ParseFunctionHelper(pipeline, | 1497 return ParseFunctionHelper(pipeline, function, |
1509 function, | 1498 /* optimized = */ false, kNoOSRDeoptId); |
1510 /* optimized = */ false, | |
1511 kNoOSRDeoptId); | |
1512 } | 1499 } |
1513 | 1500 |
1514 | 1501 |
1515 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 1502 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
1516 const Function& function) { | 1503 const Function& function) { |
1517 if (function.unoptimized_code() != Object::null()) { | 1504 if (function.unoptimized_code() != Object::null()) { |
1518 return Error::null(); | 1505 return Error::null(); |
1519 } | 1506 } |
1520 Code& original_code = Code::ZoneHandle(thread->zone()); | 1507 Code& original_code = Code::ZoneHandle(thread->zone()); |
1521 if (function.HasCode()) { | 1508 if (function.HasCode()) { |
1522 original_code = function.CurrentCode(); | 1509 original_code = function.CurrentCode(); |
1523 } | 1510 } |
1524 CompilationPipeline* pipeline = | 1511 CompilationPipeline* pipeline = |
1525 CompilationPipeline::New(thread->zone(), function); | 1512 CompilationPipeline::New(thread->zone(), function); |
1526 const Error& error = Error::Handle( | 1513 const Error& error = Error::Handle( |
1527 CompileFunctionHelper(pipeline, | 1514 CompileFunctionHelper(pipeline, function, false, /* not optimized */ |
1528 function, | |
1529 false, /* not optimized */ | |
1530 kNoOSRDeoptId)); | 1515 kNoOSRDeoptId)); |
1531 if (!error.IsNull()) { | 1516 if (!error.IsNull()) { |
1532 return error.raw(); | 1517 return error.raw(); |
1533 } | 1518 } |
1534 // Since CompileFunctionHelper replaces the current code, re-attach the | 1519 // Since CompileFunctionHelper replaces the current code, re-attach the |
1535 // the original code if the function was already compiled. | 1520 // the original code if the function was already compiled. |
1536 if (!original_code.IsNull() && | 1521 if (!original_code.IsNull() && |
1537 (original_code.raw() != function.CurrentCode())) { | 1522 (original_code.raw() != function.CurrentCode())) { |
1538 function.AttachCode(original_code); | 1523 function.AttachCode(original_code); |
1539 } | 1524 } |
1540 ASSERT(function.unoptimized_code() != Object::null()); | 1525 ASSERT(function.unoptimized_code() != Object::null()); |
1541 if (FLAG_trace_compiler) { | 1526 if (FLAG_trace_compiler) { |
1542 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); | 1527 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); |
1543 } | 1528 } |
1544 return Error::null(); | 1529 return Error::null(); |
1545 } | 1530 } |
1546 | 1531 |
1547 | 1532 |
1548 RawError* Compiler::CompileOptimizedFunction(Thread* thread, | 1533 RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
1549 const Function& function, | 1534 const Function& function, |
1550 intptr_t osr_id) { | 1535 intptr_t osr_id) { |
1551 NOT_IN_PRODUCT( | 1536 #if !defined(PRODUCT) |
1552 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); | 1537 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); |
1553 const char* event_name; | 1538 const char* event_name; |
1554 if (osr_id != kNoOSRDeoptId) { | 1539 if (osr_id != kNoOSRDeoptId) { |
1555 event_name = "CompileFunctionOptimizedOSR"; | 1540 event_name = "CompileFunctionOptimizedOSR"; |
1556 } else if (IsBackgroundCompilation()) { | 1541 } else if (IsBackgroundCompilation()) { |
1557 event_name = "CompileFunctionOptimizedBackground"; | 1542 event_name = "CompileFunctionOptimizedBackground"; |
1558 } else { | 1543 } else { |
1559 event_name = "CompileFunctionOptimized"; | 1544 event_name = "CompileFunctionOptimized"; |
1560 } | 1545 } |
1561 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, event_name, function); | 1546 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, event_name, function); |
1562 ) // !PRODUCT | 1547 #endif // !defined(PRODUCT) |
1563 | 1548 |
1564 // If we are in the optimizing in the mutator/Dart thread, then | 1549 // If we are in the optimizing in the mutator/Dart thread, then |
1565 // this is either an OSR compilation or background compilation is | 1550 // this is either an OSR compilation or background compilation is |
1566 // not currently allowed. | 1551 // not currently allowed. |
1567 ASSERT(!thread->IsMutatorThread() || | 1552 ASSERT(!thread->IsMutatorThread() || (osr_id != kNoOSRDeoptId) || |
1568 (osr_id != kNoOSRDeoptId) || | |
1569 !FLAG_background_compilation || BackgroundCompiler::IsDisabled()); | 1553 !FLAG_background_compilation || BackgroundCompiler::IsDisabled()); |
1570 CompilationPipeline* pipeline = | 1554 CompilationPipeline* pipeline = |
1571 CompilationPipeline::New(thread->zone(), function); | 1555 CompilationPipeline::New(thread->zone(), function); |
1572 return CompileFunctionHelper(pipeline, | 1556 return CompileFunctionHelper(pipeline, function, true, /* optimized */ |
1573 function, | |
1574 true, /* optimized */ | |
1575 osr_id); | 1557 osr_id); |
1576 } | 1558 } |
1577 | 1559 |
1578 | 1560 |
1579 // This is only used from unit tests. | 1561 // This is only used from unit tests. |
1580 RawError* Compiler::CompileParsedFunction( | 1562 RawError* Compiler::CompileParsedFunction(ParsedFunction* parsed_function) { |
1581 ParsedFunction* parsed_function) { | |
1582 LongJumpScope jump; | 1563 LongJumpScope jump; |
1583 if (setjmp(*jump.Set()) == 0) { | 1564 if (setjmp(*jump.Set()) == 0) { |
1584 // Non-optimized code generator. | 1565 // Non-optimized code generator. |
1585 DartCompilationPipeline pipeline; | 1566 DartCompilationPipeline pipeline; |
1586 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); | 1567 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
1587 helper.Compile(&pipeline); | 1568 helper.Compile(&pipeline); |
1588 if (FLAG_disassemble) { | 1569 if (FLAG_disassemble) { |
1589 Disassembler::DisassembleCode(parsed_function->function(), false); | 1570 Disassembler::DisassembleCode(parsed_function->function(), false); |
1590 } | 1571 } |
1591 return Error::null(); | 1572 return Error::null(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1636 // Class dynamic lives in the vm isolate. Its array fields cannot be set to | 1617 // Class dynamic lives in the vm isolate. Its array fields cannot be set to |
1637 // an empty array. | 1618 // an empty array. |
1638 if (functions.IsNull()) { | 1619 if (functions.IsNull()) { |
1639 ASSERT(cls.IsDynamicClass()); | 1620 ASSERT(cls.IsDynamicClass()); |
1640 return error.raw(); | 1621 return error.raw(); |
1641 } | 1622 } |
1642 // Compile all the regular functions. | 1623 // Compile all the regular functions. |
1643 for (int i = 0; i < functions.Length(); i++) { | 1624 for (int i = 0; i < functions.Length(); i++) { |
1644 func ^= functions.At(i); | 1625 func ^= functions.At(i); |
1645 ASSERT(!func.IsNull()); | 1626 ASSERT(!func.IsNull()); |
1646 if (!func.HasCode() && | 1627 if (!func.HasCode() && !func.is_abstract() && |
1647 !func.is_abstract() && | |
1648 !func.IsRedirectingFactory()) { | 1628 !func.IsRedirectingFactory()) { |
1649 if ((cls.is_mixin_app_alias() || cls.IsMixinApplication()) && | 1629 if ((cls.is_mixin_app_alias() || cls.IsMixinApplication()) && |
1650 func.HasOptionalParameters()) { | 1630 func.HasOptionalParameters()) { |
1651 // Skipping optional parameters in mixin application. | 1631 // Skipping optional parameters in mixin application. |
1652 continue; | 1632 continue; |
1653 } | 1633 } |
1654 error = CompileFunction(thread, func); | 1634 error = CompileFunction(thread, func); |
1655 if (!error.IsNull()) { | 1635 if (!error.IsNull()) { |
1656 return error.raw(); | 1636 return error.raw(); |
1657 } | 1637 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1710 LongJumpScope jump; | 1690 LongJumpScope jump; |
1711 if (setjmp(*jump.Set()) == 0) { | 1691 if (setjmp(*jump.Set()) == 0) { |
1712 Thread* const thread = Thread::Current(); | 1692 Thread* const thread = Thread::Current(); |
1713 NoOOBMessageScope no_msg_scope(thread); | 1693 NoOOBMessageScope no_msg_scope(thread); |
1714 NoReloadScope no_reload_scope(thread->isolate(), thread); | 1694 NoReloadScope no_reload_scope(thread->isolate(), thread); |
1715 // Under lazy compilation initializer has not yet been created, so create | 1695 // Under lazy compilation initializer has not yet been created, so create |
1716 // it now, but don't bother remembering it because it won't be used again. | 1696 // it now, but don't bother remembering it because it won't be used again. |
1717 ASSERT(!field.HasPrecompiledInitializer()); | 1697 ASSERT(!field.HasPrecompiledInitializer()); |
1718 Function& initializer = Function::Handle(thread->zone()); | 1698 Function& initializer = Function::Handle(thread->zone()); |
1719 { | 1699 { |
1720 NOT_IN_PRODUCT( | 1700 #if !defined(PRODUCT) |
1721 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); | 1701 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
1722 TimelineDurationScope tds(thread, Timeline::GetCompilerStream(), | 1702 TimelineDurationScope tds(thread, Timeline::GetCompilerStream(), |
1723 "CompileStaticInitializer"); | 1703 "CompileStaticInitializer"); |
1724 if (tds.enabled()) { | 1704 if (tds.enabled()) { |
1725 tds.SetNumArguments(1); | 1705 tds.SetNumArguments(1); |
1726 tds.CopyArgument(0, "field", field.ToCString()); | 1706 tds.CopyArgument(0, "field", field.ToCString()); |
1727 } | 1707 } |
1728 ) | 1708 #endif // !defined(PRODUCT) |
1729 | 1709 |
1730 StackZone stack_zone(thread); | 1710 StackZone stack_zone(thread); |
1731 Zone* zone = stack_zone.GetZone(); | 1711 Zone* zone = stack_zone.GetZone(); |
1732 ParsedFunction* parsed_function; | 1712 ParsedFunction* parsed_function; |
1733 | 1713 |
1734 // Create a one-time-use function to evaluate the initializer and invoke | 1714 // Create a one-time-use function to evaluate the initializer and invoke |
1735 // it immediately. | 1715 // it immediately. |
1736 if (field.kernel_field() != NULL) { | 1716 if (field.kernel_field() != NULL) { |
1737 // kImplicitStaticFinalGetter is used for both implicit static getters | 1717 // kImplicitStaticFinalGetter is used for both implicit static getters |
1738 // and static initializers. The Kernel graph builder will tell the | 1718 // and static initializers. The Kernel graph builder will tell the |
1739 // difference by pattern matching on the name. | 1719 // difference by pattern matching on the name. |
1740 const String& name = String::Handle(zone, | 1720 const String& name = String::Handle( |
1741 Symbols::FromConcat(thread, | 1721 zone, Symbols::FromConcat(thread, Symbols::InitPrefix(), |
1742 Symbols::InitPrefix(), String::Handle(zone, field.name()))); | 1722 String::Handle(zone, field.name()))); |
1743 const Script& script = Script::Handle(zone, field.Script()); | 1723 const Script& script = Script::Handle(zone, field.Script()); |
1744 Object& owner = Object::Handle(zone, field.Owner()); | 1724 Object& owner = Object::Handle(zone, field.Owner()); |
1745 owner = PatchClass::New(Class::Cast(owner), script); | 1725 owner = PatchClass::New(Class::Cast(owner), script); |
1746 const Function& function = Function::ZoneHandle(zone, | 1726 const Function& function = Function::ZoneHandle( |
1747 Function::New(name, | 1727 zone, Function::New(name, RawFunction::kImplicitStaticFinalGetter, |
1748 RawFunction::kImplicitStaticFinalGetter, | 1728 true, // is_static |
1749 true, // is_static | 1729 false, // is_const |
1750 false, // is_const | 1730 false, // is_abstract |
1751 false, // is_abstract | 1731 false, // is_external |
1752 false, // is_external | 1732 false, // is_native |
1753 false, // is_native | 1733 owner, TokenPosition::kNoSource)); |
1754 owner, | |
1755 TokenPosition::kNoSource)); | |
1756 function.set_kernel_function(field.kernel_field()); | 1734 function.set_kernel_function(field.kernel_field()); |
1757 function.set_result_type(AbstractType::Handle(zone, field.type())); | 1735 function.set_result_type(AbstractType::Handle(zone, field.type())); |
1758 function.set_is_reflectable(false); | 1736 function.set_is_reflectable(false); |
1759 function.set_is_debuggable(false); | 1737 function.set_is_debuggable(false); |
1760 function.set_is_inlinable(false); | 1738 function.set_is_inlinable(false); |
1761 parsed_function = new(zone) ParsedFunction(thread, function); | 1739 parsed_function = new (zone) ParsedFunction(thread, function); |
1762 } else { | 1740 } else { |
1763 parsed_function = Parser::ParseStaticFieldInitializer(field); | 1741 parsed_function = Parser::ParseStaticFieldInitializer(field); |
1764 parsed_function->AllocateVariables(); | 1742 parsed_function->AllocateVariables(); |
1765 } | 1743 } |
1766 | 1744 |
1767 // Non-optimized code generator. | 1745 // Non-optimized code generator. |
1768 DartCompilationPipeline pipeline; | 1746 DartCompilationPipeline pipeline; |
1769 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); | 1747 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
1770 helper.Compile(&pipeline); | 1748 helper.Compile(&pipeline); |
1771 initializer = parsed_function->function().raw(); | 1749 initializer = parsed_function->function().raw(); |
1772 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( | 1750 Code::Handle(initializer.unoptimized_code()) |
1773 Object::empty_var_descriptors()); | 1751 .set_var_descriptors(Object::empty_var_descriptors()); |
1774 } | 1752 } |
1775 // Invoke the function to evaluate the expression. | 1753 // Invoke the function to evaluate the expression. |
1776 return DartEntry::InvokeFunction(initializer, Object::empty_array()); | 1754 return DartEntry::InvokeFunction(initializer, Object::empty_array()); |
1777 } else { | 1755 } else { |
1778 Thread* const thread = Thread::Current(); | 1756 Thread* const thread = Thread::Current(); |
1779 StackZone zone(thread); | 1757 StackZone zone(thread); |
1780 const Error& error = Error::Handle(thread->zone(), thread->sticky_error()); | 1758 const Error& error = Error::Handle(thread->zone(), thread->sticky_error()); |
1781 thread->clear_sticky_error(); | 1759 thread->clear_sticky_error(); |
1782 return error.raw(); | 1760 return error.raw(); |
1783 } | 1761 } |
1784 UNREACHABLE(); | 1762 UNREACHABLE(); |
1785 return Object::null(); | 1763 return Object::null(); |
1786 } | 1764 } |
1787 | 1765 |
1788 | 1766 |
1789 | |
1790 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { | 1767 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
1791 #ifdef DART_PRECOMPILER | 1768 #ifdef DART_PRECOMPILER |
1792 if (FLAG_precompiled_mode) { | 1769 if (FLAG_precompiled_mode) { |
1793 return Precompiler::ExecuteOnce(fragment); | 1770 return Precompiler::ExecuteOnce(fragment); |
1794 } | 1771 } |
1795 #endif | 1772 #endif |
1796 LongJumpScope jump; | 1773 LongJumpScope jump; |
1797 if (setjmp(*jump.Set()) == 0) { | 1774 if (setjmp(*jump.Set()) == 0) { |
1798 Thread* const thread = Thread::Current(); | 1775 Thread* const thread = Thread::Current(); |
1799 | 1776 |
(...skipping 12 matching lines...) Expand all Loading... |
1812 } | 1789 } |
1813 } | 1790 } |
1814 | 1791 |
1815 // Create a dummy function object for the code generator. | 1792 // Create a dummy function object for the code generator. |
1816 // The function needs to be associated with a named Class: the interface | 1793 // The function needs to be associated with a named Class: the interface |
1817 // Function fits the bill. | 1794 // Function fits the bill. |
1818 const char* kEvalConst = "eval_const"; | 1795 const char* kEvalConst = "eval_const"; |
1819 const Function& func = Function::ZoneHandle(Function::New( | 1796 const Function& func = Function::ZoneHandle(Function::New( |
1820 String::Handle(Symbols::New(thread, kEvalConst)), | 1797 String::Handle(Symbols::New(thread, kEvalConst)), |
1821 RawFunction::kRegularFunction, | 1798 RawFunction::kRegularFunction, |
1822 true, // static function | 1799 true, // static function |
1823 false, // not const function | 1800 false, // not const function |
1824 false, // not abstract | 1801 false, // not abstract |
1825 false, // not external | 1802 false, // not external |
1826 false, // not native | 1803 false, // not native |
1827 Class::Handle(Type::Handle(Type::DartFunctionType()).type_class()), | 1804 Class::Handle(Type::Handle(Type::DartFunctionType()).type_class()), |
1828 fragment->token_pos())); | 1805 fragment->token_pos())); |
1829 | 1806 |
1830 func.set_result_type(Object::dynamic_type()); | 1807 func.set_result_type(Object::dynamic_type()); |
1831 func.set_num_fixed_parameters(0); | 1808 func.set_num_fixed_parameters(0); |
1832 func.SetNumOptionalParameters(0, true); | 1809 func.SetNumOptionalParameters(0, true); |
1833 // Manually generated AST, do not recompile. | 1810 // Manually generated AST, do not recompile. |
1834 func.SetIsOptimizable(false); | 1811 func.SetIsOptimizable(false); |
1835 func.set_is_debuggable(false); | 1812 func.set_is_debuggable(false); |
1836 | 1813 |
1837 // We compile the function here, even though InvokeFunction() below | 1814 // We compile the function here, even though InvokeFunction() below |
1838 // would compile func automatically. We are checking fewer invariants | 1815 // would compile func automatically. We are checking fewer invariants |
1839 // here. | 1816 // here. |
1840 ParsedFunction* parsed_function = new ParsedFunction(thread, func); | 1817 ParsedFunction* parsed_function = new ParsedFunction(thread, func); |
1841 parsed_function->SetNodeSequence(fragment); | 1818 parsed_function->SetNodeSequence(fragment); |
1842 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); | 1819 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); |
1843 fragment->scope()->AddVariable( | 1820 fragment->scope()->AddVariable(parsed_function->current_context_var()); |
1844 parsed_function->current_context_var()); | |
1845 parsed_function->AllocateVariables(); | 1821 parsed_function->AllocateVariables(); |
1846 | 1822 |
1847 // Non-optimized code generator. | 1823 // Non-optimized code generator. |
1848 DartCompilationPipeline pipeline; | 1824 DartCompilationPipeline pipeline; |
1849 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); | 1825 CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
1850 helper.Compile(&pipeline); | 1826 helper.Compile(&pipeline); |
1851 Code::Handle(func.unoptimized_code()).set_var_descriptors( | 1827 Code::Handle(func.unoptimized_code()) |
1852 Object::empty_var_descriptors()); | 1828 .set_var_descriptors(Object::empty_var_descriptors()); |
1853 | 1829 |
1854 const Object& result = PassiveObject::Handle( | 1830 const Object& result = PassiveObject::Handle( |
1855 DartEntry::InvokeFunction(func, Object::empty_array())); | 1831 DartEntry::InvokeFunction(func, Object::empty_array())); |
1856 return result.raw(); | 1832 return result.raw(); |
1857 } else { | 1833 } else { |
1858 Thread* const thread = Thread::Current(); | 1834 Thread* const thread = Thread::Current(); |
1859 const Object& result = PassiveObject::Handle(thread->sticky_error()); | 1835 const Object& result = PassiveObject::Handle(thread->sticky_error()); |
1860 thread->clear_sticky_error(); | 1836 thread->clear_sticky_error(); |
1861 return result.raw(); | 1837 return result.raw(); |
1862 } | 1838 } |
1863 UNREACHABLE(); | 1839 UNREACHABLE(); |
1864 return Object::null(); | 1840 return Object::null(); |
1865 } | 1841 } |
1866 | 1842 |
1867 | 1843 |
1868 void Compiler::AbortBackgroundCompilation(intptr_t deopt_id, const char* msg) { | 1844 void Compiler::AbortBackgroundCompilation(intptr_t deopt_id, const char* msg) { |
1869 if (FLAG_trace_compiler) { | 1845 if (FLAG_trace_compiler) { |
1870 THR_Print("ABORT background compilation: %s\n", msg); | 1846 THR_Print("ABORT background compilation: %s\n", msg); |
1871 } | 1847 } |
1872 NOT_IN_PRODUCT( | 1848 #if !defined(PRODUCT) |
1873 TimelineStream* stream = Timeline::GetCompilerStream(); | 1849 TimelineStream* stream = Timeline::GetCompilerStream(); |
1874 ASSERT(stream != NULL); | 1850 ASSERT(stream != NULL); |
1875 TimelineEvent* event = stream->StartEvent(); | 1851 TimelineEvent* event = stream->StartEvent(); |
1876 if (event != NULL) { | 1852 if (event != NULL) { |
1877 event->Instant("AbortBackgroundCompilation"); | 1853 event->Instant("AbortBackgroundCompilation"); |
1878 event->SetNumArguments(1); | 1854 event->SetNumArguments(1); |
1879 event->CopyArgument(0, "reason", msg); | 1855 event->CopyArgument(0, "reason", msg); |
1880 event->Complete(); | 1856 event->Complete(); |
1881 } | 1857 } |
1882 ) // !PRODUCT | 1858 #endif // !defined(PRODUCT) |
1883 ASSERT(Compiler::IsBackgroundCompilation()); | 1859 ASSERT(Compiler::IsBackgroundCompilation()); |
1884 Thread::Current()->long_jump_base()->Jump( | 1860 Thread::Current()->long_jump_base()->Jump( |
1885 deopt_id, Object::background_compilation_error()); | 1861 deopt_id, Object::background_compilation_error()); |
1886 } | 1862 } |
1887 | 1863 |
1888 | 1864 |
1889 // C-heap allocated background compilation queue element. | 1865 // C-heap allocated background compilation queue element. |
1890 class QueueElement { | 1866 class QueueElement { |
1891 public: | 1867 public: |
1892 explicit QueueElement(const Function& function) | 1868 explicit QueueElement(const Function& function) |
1893 : next_(NULL), | 1869 : next_(NULL), function_(function.raw()) {} |
1894 function_(function.raw()) { | |
1895 } | |
1896 | 1870 |
1897 virtual ~QueueElement() { | 1871 virtual ~QueueElement() { |
1898 next_ = NULL; | 1872 next_ = NULL; |
1899 function_ = Function::null(); | 1873 function_ = Function::null(); |
1900 } | 1874 } |
1901 | 1875 |
1902 RawFunction* Function() const { return function_; } | 1876 RawFunction* Function() const { return function_; } |
1903 | 1877 |
1904 | 1878 |
1905 void set_next(QueueElement* elem) { next_ = elem; } | 1879 void set_next(QueueElement* elem) { next_ = elem; } |
(...skipping 10 matching lines...) Expand all Loading... |
1916 | 1890 |
1917 DISALLOW_COPY_AND_ASSIGN(QueueElement); | 1891 DISALLOW_COPY_AND_ASSIGN(QueueElement); |
1918 }; | 1892 }; |
1919 | 1893 |
1920 | 1894 |
1921 // Allocated in C-heap. Handles both input and output of background compilation. | 1895 // Allocated in C-heap. Handles both input and output of background compilation. |
1922 // It implements a FIFO queue, using Peek, Add, Remove operations. | 1896 // It implements a FIFO queue, using Peek, Add, Remove operations. |
1923 class BackgroundCompilationQueue { | 1897 class BackgroundCompilationQueue { |
1924 public: | 1898 public: |
1925 BackgroundCompilationQueue() : first_(NULL), last_(NULL) {} | 1899 BackgroundCompilationQueue() : first_(NULL), last_(NULL) {} |
1926 virtual ~BackgroundCompilationQueue() { | 1900 virtual ~BackgroundCompilationQueue() { Clear(); } |
1927 Clear(); | |
1928 } | |
1929 | 1901 |
1930 void VisitObjectPointers(ObjectPointerVisitor* visitor) { | 1902 void VisitObjectPointers(ObjectPointerVisitor* visitor) { |
1931 ASSERT(visitor != NULL); | 1903 ASSERT(visitor != NULL); |
1932 QueueElement* p = first_; | 1904 QueueElement* p = first_; |
1933 while (p != NULL) { | 1905 while (p != NULL) { |
1934 visitor->VisitPointer(p->function_ptr()); | 1906 visitor->VisitPointer(p->function_ptr()); |
1935 p = p->next(); | 1907 p = p->next(); |
1936 } | 1908 } |
1937 } | 1909 } |
1938 | 1910 |
1939 bool IsEmpty() const { return first_ == NULL; } | 1911 bool IsEmpty() const { return first_ == NULL; } |
1940 | 1912 |
1941 void Add(QueueElement* value) { | 1913 void Add(QueueElement* value) { |
1942 ASSERT(value != NULL); | 1914 ASSERT(value != NULL); |
1943 ASSERT(value->next() == NULL); | 1915 ASSERT(value->next() == NULL); |
1944 if (first_ == NULL) { | 1916 if (first_ == NULL) { |
1945 first_ = value; | 1917 first_ = value; |
1946 ASSERT(last_ == NULL); | 1918 ASSERT(last_ == NULL); |
1947 } else { | 1919 } else { |
1948 ASSERT(last_ != NULL); | 1920 ASSERT(last_ != NULL); |
1949 last_->set_next(value); | 1921 last_->set_next(value); |
1950 } | 1922 } |
1951 last_ = value; | 1923 last_ = value; |
1952 ASSERT(first_ != NULL && last_ != NULL); | 1924 ASSERT(first_ != NULL && last_ != NULL); |
1953 } | 1925 } |
1954 | 1926 |
1955 QueueElement* Peek() const { | 1927 QueueElement* Peek() const { return first_; } |
1956 return first_; | |
1957 } | |
1958 | 1928 |
1959 RawFunction* PeekFunction() const { | 1929 RawFunction* PeekFunction() const { |
1960 QueueElement* e = Peek(); | 1930 QueueElement* e = Peek(); |
1961 if (e == NULL) { | 1931 if (e == NULL) { |
1962 return Function::null(); | 1932 return Function::null(); |
1963 } else { | 1933 } else { |
1964 return e->Function(); | 1934 return e->Function(); |
1965 } | 1935 } |
1966 } | 1936 } |
1967 | 1937 |
(...skipping 28 matching lines...) Expand all Loading... |
1996 | 1966 |
1997 private: | 1967 private: |
1998 QueueElement* first_; | 1968 QueueElement* first_; |
1999 QueueElement* last_; | 1969 QueueElement* last_; |
2000 | 1970 |
2001 DISALLOW_COPY_AND_ASSIGN(BackgroundCompilationQueue); | 1971 DISALLOW_COPY_AND_ASSIGN(BackgroundCompilationQueue); |
2002 }; | 1972 }; |
2003 | 1973 |
2004 | 1974 |
2005 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) | 1975 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) |
2006 : isolate_(isolate), running_(true), done_(new bool()), | 1976 : isolate_(isolate), |
2007 queue_monitor_(new Monitor()), done_monitor_(new Monitor()), | 1977 running_(true), |
| 1978 done_(new bool()), |
| 1979 queue_monitor_(new Monitor()), |
| 1980 done_monitor_(new Monitor()), |
2008 function_queue_(new BackgroundCompilationQueue()) { | 1981 function_queue_(new BackgroundCompilationQueue()) { |
2009 *done_ = false; | 1982 *done_ = false; |
2010 } | 1983 } |
2011 | 1984 |
2012 | 1985 |
2013 // Fields all deleted in ::Stop; here clear them. | 1986 // Fields all deleted in ::Stop; here clear them. |
2014 BackgroundCompiler::~BackgroundCompiler() { | 1987 BackgroundCompiler::~BackgroundCompiler() { |
2015 isolate_ = NULL; | 1988 isolate_ = NULL; |
2016 running_ = false; | 1989 running_ = false; |
2017 done_ = NULL; | 1990 done_ = NULL; |
2018 queue_monitor_ = NULL; | 1991 queue_monitor_ = NULL; |
2019 done_monitor_ = NULL; | 1992 done_monitor_ = NULL; |
2020 function_queue_ = NULL; | 1993 function_queue_ = NULL; |
2021 } | 1994 } |
2022 | 1995 |
2023 | 1996 |
2024 void BackgroundCompiler::Run() { | 1997 void BackgroundCompiler::Run() { |
2025 while (running_) { | 1998 while (running_) { |
2026 // Maybe something is already in the queue, check first before waiting | 1999 // Maybe something is already in the queue, check first before waiting |
2027 // to be notified. | 2000 // to be notified. |
2028 bool result = Thread::EnterIsolateAsHelper(isolate_, Thread::kCompilerTask); | 2001 bool result = Thread::EnterIsolateAsHelper(isolate_, Thread::kCompilerTask); |
2029 ASSERT(result); | 2002 ASSERT(result); |
2030 { | 2003 { |
2031 Thread* thread = Thread::Current(); | 2004 Thread* thread = Thread::Current(); |
2032 StackZone stack_zone(thread); | 2005 StackZone stack_zone(thread); |
2033 Zone* zone = stack_zone.GetZone(); | 2006 Zone* zone = stack_zone.GetZone(); |
2034 HANDLESCOPE(thread); | 2007 HANDLESCOPE(thread); |
2035 Function& function = Function::Handle(zone); | 2008 Function& function = Function::Handle(zone); |
2036 { MonitorLocker ml(queue_monitor_); | 2009 { |
| 2010 MonitorLocker ml(queue_monitor_); |
2037 function = function_queue()->PeekFunction(); | 2011 function = function_queue()->PeekFunction(); |
2038 } | 2012 } |
2039 while (running_ && !function.IsNull() && !isolate_->IsTopLevelParsing()) { | 2013 while (running_ && !function.IsNull() && !isolate_->IsTopLevelParsing()) { |
2040 // Check that we have aggregated and cleared the stats. | 2014 // Check that we have aggregated and cleared the stats. |
2041 ASSERT(thread->compiler_stats()->IsCleared()); | 2015 ASSERT(thread->compiler_stats()->IsCleared()); |
2042 Compiler::CompileOptimizedFunction(thread, | 2016 Compiler::CompileOptimizedFunction(thread, function, |
2043 function, | |
2044 Compiler::kNoOSRDeoptId); | 2017 Compiler::kNoOSRDeoptId); |
2045 #ifndef PRODUCT | 2018 #ifndef PRODUCT |
2046 Isolate* isolate = thread->isolate(); | 2019 Isolate* isolate = thread->isolate(); |
2047 isolate->aggregate_compiler_stats()->Add(*thread->compiler_stats()); | 2020 isolate->aggregate_compiler_stats()->Add(*thread->compiler_stats()); |
2048 thread->compiler_stats()->Clear(); | 2021 thread->compiler_stats()->Clear(); |
2049 #endif // PRODUCT | 2022 #endif // PRODUCT |
2050 | 2023 |
2051 QueueElement* qelem = NULL; | 2024 QueueElement* qelem = NULL; |
2052 { MonitorLocker ml(queue_monitor_); | 2025 { |
| 2026 MonitorLocker ml(queue_monitor_); |
2053 if (function_queue()->IsEmpty()) { | 2027 if (function_queue()->IsEmpty()) { |
2054 // We are shutting down, queue was cleared. | 2028 // We are shutting down, queue was cleared. |
2055 function = Function::null(); | 2029 function = Function::null(); |
2056 } else { | 2030 } else { |
2057 qelem = function_queue()->Remove(); | 2031 qelem = function_queue()->Remove(); |
2058 const Function& old = Function::Handle(qelem->Function()); | 2032 const Function& old = Function::Handle(qelem->Function()); |
2059 if ((!old.HasOptimizedCode() && old.IsOptimizable()) || | 2033 if ((!old.HasOptimizedCode() && old.IsOptimizable()) || |
2060 FLAG_stress_test_background_compilation) { | 2034 FLAG_stress_test_background_compilation) { |
2061 if (Compiler::CanOptimizeFunction(thread, old)) { | 2035 if (Compiler::CanOptimizeFunction(thread, old)) { |
2062 QueueElement* repeat_qelem = new QueueElement(old); | 2036 QueueElement* repeat_qelem = new QueueElement(old); |
2063 function_queue()->Add(repeat_qelem); | 2037 function_queue()->Add(repeat_qelem); |
2064 } | 2038 } |
2065 } | 2039 } |
2066 function = function_queue()->PeekFunction(); | 2040 function = function_queue()->PeekFunction(); |
2067 } | 2041 } |
2068 } | 2042 } |
2069 if (qelem != NULL) { | 2043 if (qelem != NULL) { |
2070 delete qelem; | 2044 delete qelem; |
2071 } | 2045 } |
2072 } | 2046 } |
2073 } | 2047 } |
2074 Thread::ExitIsolateAsHelper(); | 2048 Thread::ExitIsolateAsHelper(); |
2075 { | 2049 { |
2076 // Wait to be notified when the work queue is not empty. | 2050 // Wait to be notified when the work queue is not empty. |
2077 MonitorLocker ml(queue_monitor_); | 2051 MonitorLocker ml(queue_monitor_); |
2078 while ((function_queue()->IsEmpty() || isolate_->IsTopLevelParsing()) | 2052 while ((function_queue()->IsEmpty() || isolate_->IsTopLevelParsing()) && |
2079 && running_) { | 2053 running_) { |
2080 ml.Wait(); | 2054 ml.Wait(); |
2081 } | 2055 } |
2082 } | 2056 } |
2083 } // while running | 2057 } // while running |
2084 | 2058 |
2085 { | 2059 { |
2086 // Notify that the thread is done. | 2060 // Notify that the thread is done. |
2087 MonitorLocker ml_done(done_monitor_); | 2061 MonitorLocker ml_done(done_monitor_); |
2088 *done_ = true; | 2062 *done_ = true; |
2089 ml_done.Notify(); | 2063 ml_done.Notify(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2127 Monitor* queue_monitor = task->queue_monitor_; | 2101 Monitor* queue_monitor = task->queue_monitor_; |
2128 Monitor* done_monitor = task->done_monitor_; | 2102 Monitor* done_monitor = task->done_monitor_; |
2129 bool* task_done = task->done_; | 2103 bool* task_done = task->done_; |
2130 // Wake up compiler task and stop it. | 2104 // Wake up compiler task and stop it. |
2131 { | 2105 { |
2132 MonitorLocker ml(queue_monitor); | 2106 MonitorLocker ml(queue_monitor); |
2133 task->running_ = false; | 2107 task->running_ = false; |
2134 function_queue->Clear(); | 2108 function_queue->Clear(); |
2135 // 'task' will be deleted by thread pool. | 2109 // 'task' will be deleted by thread pool. |
2136 task = NULL; | 2110 task = NULL; |
2137 ml.Notify(); // Stop waiting for the queue. | 2111 ml.Notify(); // Stop waiting for the queue. |
2138 } | 2112 } |
2139 | 2113 |
2140 { | 2114 { |
2141 MonitorLocker ml_done(done_monitor); | 2115 MonitorLocker ml_done(done_monitor); |
2142 while (!(*task_done)) { | 2116 while (!(*task_done)) { |
2143 ml_done.WaitWithSafepointCheck(Thread::Current()); | 2117 ml_done.WaitWithSafepointCheck(Thread::Current()); |
2144 } | 2118 } |
2145 } | 2119 } |
2146 delete task_done; | 2120 delete task_done; |
2147 delete done_monitor; | 2121 delete done_monitor; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2183 Isolate* isolate = thread->isolate(); | 2157 Isolate* isolate = thread->isolate(); |
2184 MutexLocker ml(isolate->mutex()); | 2158 MutexLocker ml(isolate->mutex()); |
2185 isolate->enable_background_compiler(); | 2159 isolate->enable_background_compiler(); |
2186 } | 2160 } |
2187 | 2161 |
2188 | 2162 |
2189 void BackgroundCompiler::EnsureInit(Thread* thread) { | 2163 void BackgroundCompiler::EnsureInit(Thread* thread) { |
2190 ASSERT(thread->IsMutatorThread()); | 2164 ASSERT(thread->IsMutatorThread()); |
2191 // Finalize NoSuchMethodError, _Mint; occasionally needed in optimized | 2165 // Finalize NoSuchMethodError, _Mint; occasionally needed in optimized |
2192 // compilation. | 2166 // compilation. |
2193 Class& cls = Class::Handle(thread->zone(), | 2167 Class& cls = Class::Handle( |
2194 Library::LookupCoreClass(Symbols::NoSuchMethodError())); | 2168 thread->zone(), Library::LookupCoreClass(Symbols::NoSuchMethodError())); |
2195 ASSERT(!cls.IsNull()); | 2169 ASSERT(!cls.IsNull()); |
2196 Error& error = Error::Handle(thread->zone(), | 2170 Error& error = Error::Handle(thread->zone(), cls.EnsureIsFinalized(thread)); |
2197 cls.EnsureIsFinalized(thread)); | |
2198 ASSERT(error.IsNull()); | 2171 ASSERT(error.IsNull()); |
2199 cls = Library::LookupCoreClass(Symbols::_Mint()); | 2172 cls = Library::LookupCoreClass(Symbols::_Mint()); |
2200 ASSERT(!cls.IsNull()); | 2173 ASSERT(!cls.IsNull()); |
2201 error = cls.EnsureIsFinalized(thread); | 2174 error = cls.EnsureIsFinalized(thread); |
2202 ASSERT(error.IsNull()); | 2175 ASSERT(error.IsNull()); |
2203 | 2176 |
2204 bool start_task = false; | 2177 bool start_task = false; |
2205 Isolate* isolate = thread->isolate(); | 2178 Isolate* isolate = thread->isolate(); |
2206 { | 2179 { |
2207 MutexLocker ml(isolate->mutex()); | 2180 MutexLocker ml(isolate->mutex()); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2258 return Error::null(); | 2231 return Error::null(); |
2259 } | 2232 } |
2260 | 2233 |
2261 | 2234 |
2262 RawError* Compiler::CompileClass(const Class& cls) { | 2235 RawError* Compiler::CompileClass(const Class& cls) { |
2263 UNREACHABLE(); | 2236 UNREACHABLE(); |
2264 return Error::null(); | 2237 return Error::null(); |
2265 } | 2238 } |
2266 | 2239 |
2267 | 2240 |
2268 RawError* Compiler::CompileFunction(Thread* thread, | 2241 RawError* Compiler::CompileFunction(Thread* thread, const Function& function) { |
2269 const Function& function) { | |
2270 UNREACHABLE(); | 2242 UNREACHABLE(); |
2271 return Error::null(); | 2243 return Error::null(); |
2272 } | 2244 } |
2273 | 2245 |
2274 | 2246 |
2275 RawError* Compiler::ParseFunction(Thread* thread, | 2247 RawError* Compiler::ParseFunction(Thread* thread, const Function& function) { |
2276 const Function& function) { | |
2277 UNREACHABLE(); | 2248 UNREACHABLE(); |
2278 return Error::null(); | 2249 return Error::null(); |
2279 } | 2250 } |
2280 | 2251 |
2281 | 2252 |
2282 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 2253 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
2283 const Function& function) { | 2254 const Function& function) { |
2284 UNREACHABLE(); | 2255 UNREACHABLE(); |
2285 return Error::null(); | 2256 return Error::null(); |
2286 } | 2257 } |
2287 | 2258 |
2288 | 2259 |
2289 RawError* Compiler::CompileOptimizedFunction(Thread* thread, | 2260 RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
2290 const Function& function, | 2261 const Function& function, |
2291 intptr_t osr_id) { | 2262 intptr_t osr_id) { |
2292 UNREACHABLE(); | 2263 UNREACHABLE(); |
2293 return Error::null(); | 2264 return Error::null(); |
2294 } | 2265 } |
2295 | 2266 |
2296 | 2267 |
2297 RawError* Compiler::CompileParsedFunction( | 2268 RawError* Compiler::CompileParsedFunction(ParsedFunction* parsed_function) { |
2298 ParsedFunction* parsed_function) { | |
2299 UNREACHABLE(); | 2269 UNREACHABLE(); |
2300 return Error::null(); | 2270 return Error::null(); |
2301 } | 2271 } |
2302 | 2272 |
2303 | 2273 |
2304 void Compiler::ComputeLocalVarDescriptors(const Code& code) { | 2274 void Compiler::ComputeLocalVarDescriptors(const Code& code) { |
2305 UNREACHABLE(); | 2275 UNREACHABLE(); |
2306 } | 2276 } |
2307 | 2277 |
2308 | 2278 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2368 | 2338 |
2369 | 2339 |
2370 bool BackgroundCompiler::IsDisabled() { | 2340 bool BackgroundCompiler::IsDisabled() { |
2371 UNREACHABLE(); | 2341 UNREACHABLE(); |
2372 return true; | 2342 return true; |
2373 } | 2343 } |
2374 | 2344 |
2375 #endif // DART_PRECOMPILED_RUNTIME | 2345 #endif // DART_PRECOMPILED_RUNTIME |
2376 | 2346 |
2377 } // namespace dart | 2347 } // namespace dart |
OLD | NEW |