| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/globals.h" // Needed here to get TARGET_ARCH_XXX. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. |
| 6 | 6 |
| 7 #include "vm/flow_graph_compiler.h" | 7 #include "vm/flow_graph_compiler.h" |
| 8 | 8 |
| 9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
| 10 #include "vm/cha.h" | 10 #include "vm/cha.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/debugger.h" | 12 #include "vm/debugger.h" |
| 13 #include "vm/deopt_instructions.h" | 13 #include "vm/deopt_instructions.h" |
| 14 #include "vm/exceptions.h" | 14 #include "vm/exceptions.h" |
| 15 #include "vm/flow_graph_allocator.h" | 15 #include "vm/flow_graph_allocator.h" |
| 16 #include "vm/il_printer.h" | 16 #include "vm/il_printer.h" |
| 17 #include "vm/intrinsifier.h" | 17 #include "vm/intrinsifier.h" |
| 18 #include "vm/locations.h" | 18 #include "vm/locations.h" |
| 19 #include "vm/longjump.h" | 19 #include "vm/longjump.h" |
| 20 #include "vm/object_store.h" | 20 #include "vm/object_store.h" |
| 21 #include "vm/parser.h" | 21 #include "vm/parser.h" |
| 22 #include "vm/raw_object.h" | 22 #include "vm/raw_object.h" |
| 23 #include "vm/stack_frame.h" | 23 #include "vm/stack_frame.h" |
| 24 #include "vm/stub_code.h" | 24 #include "vm/stub_code.h" |
| 25 #include "vm/symbols.h" | 25 #include "vm/symbols.h" |
| 26 | 26 |
| 27 namespace dart { | 27 namespace dart { |
| 28 | 28 |
| 29 DEFINE_FLAG(bool, trace_inlining_intervals, false, |
| 30 "Inlining interval diagnostics"); |
| 31 DEFINE_FLAG(bool, enable_simd_inline, true, |
| 32 "Enable inlining of SIMD related method calls."); |
| 33 DEFINE_FLAG(int, min_optimization_counter_threshold, 5000, |
| 34 "The minimum invocation count for a function."); |
| 35 DEFINE_FLAG(int, optimization_counter_scale, 2000, |
| 36 "The scale of invocation count, by size of the function."); |
| 37 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); |
| 38 |
| 29 DECLARE_FLAG(bool, code_comments); | 39 DECLARE_FLAG(bool, code_comments); |
| 40 DECLARE_FLAG(int, deoptimize_every); |
| 41 DECLARE_FLAG(charp, deoptimize_filter); |
| 30 DECLARE_FLAG(bool, disassemble); | 42 DECLARE_FLAG(bool, disassemble); |
| 31 DECLARE_FLAG(bool, disassemble_optimized); | 43 DECLARE_FLAG(bool, disassemble_optimized); |
| 32 DECLARE_FLAG(bool, emit_edge_counters); | 44 DECLARE_FLAG(bool, emit_edge_counters); |
| 33 DECLARE_FLAG(bool, enable_type_checks); | 45 DECLARE_FLAG(bool, enable_type_checks); |
| 34 DECLARE_FLAG(bool, intrinsify); | 46 DECLARE_FLAG(bool, intrinsify); |
| 47 DECLARE_FLAG(int, optimization_counter_threshold); |
| 35 DECLARE_FLAG(bool, propagate_ic_data); | 48 DECLARE_FLAG(bool, propagate_ic_data); |
| 36 DECLARE_FLAG(int, optimization_counter_threshold); | |
| 37 DECLARE_FLAG(int, regexp_optimization_counter_threshold); | 49 DECLARE_FLAG(int, regexp_optimization_counter_threshold); |
| 38 DEFINE_FLAG(int, optimization_counter_scale, 2000, | |
| 39 "The scale of invocation count, by size of the function."); | |
| 40 DEFINE_FLAG(int, min_optimization_counter_threshold, 5000, | |
| 41 "The minimum invocation count for a function."); | |
| 42 DECLARE_FLAG(int, reoptimization_counter_threshold); | 50 DECLARE_FLAG(int, reoptimization_counter_threshold); |
| 51 DECLARE_FLAG(int, stacktrace_every); |
| 52 DECLARE_FLAG(charp, stacktrace_filter); |
| 43 DECLARE_FLAG(bool, use_cha); | 53 DECLARE_FLAG(bool, use_cha); |
| 44 DECLARE_FLAG(bool, use_osr); | 54 DECLARE_FLAG(bool, use_osr); |
| 45 DECLARE_FLAG(int, stacktrace_every); | |
| 46 DECLARE_FLAG(charp, stacktrace_filter); | |
| 47 DECLARE_FLAG(int, deoptimize_every); | |
| 48 DECLARE_FLAG(charp, deoptimize_filter); | |
| 49 DECLARE_FLAG(bool, warn_on_javascript_compatibility); | 55 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
| 50 DEFINE_FLAG(bool, enable_simd_inline, true, | |
| 51 "Enable inlining of SIMD related method calls."); | |
| 52 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); | |
| 53 | 56 |
| 54 // Quick access to the locally defined isolate() method. | 57 // Quick access to the locally defined isolate() method. |
| 55 #define I (isolate()) | 58 #define I (isolate()) |
| 56 | 59 |
| 57 // Assign locations to incoming arguments, i.e., values pushed above spill slots | 60 // Assign locations to incoming arguments, i.e., values pushed above spill slots |
| 58 // with PushArgument. Recursively allocates from outermost to innermost | 61 // with PushArgument. Recursively allocates from outermost to innermost |
| 59 // environment. | 62 // environment. |
| 60 void CompilerDeoptInfo::AllocateIncomingParametersRecursive( | 63 void CompilerDeoptInfo::AllocateIncomingParametersRecursive( |
| 61 Environment* env, | 64 Environment* env, |
| 62 intptr_t* stack_height) { | 65 intptr_t* stack_height) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 82 } | 85 } |
| 83 } | 86 } |
| 84 } | 87 } |
| 85 | 88 |
| 86 | 89 |
| 87 FlowGraphCompiler::FlowGraphCompiler( | 90 FlowGraphCompiler::FlowGraphCompiler( |
| 88 Assembler* assembler, | 91 Assembler* assembler, |
| 89 FlowGraph* flow_graph, | 92 FlowGraph* flow_graph, |
| 90 const ParsedFunction& parsed_function, | 93 const ParsedFunction& parsed_function, |
| 91 bool is_optimizing, | 94 bool is_optimizing, |
| 92 const GrowableArray<const Function*>& inline_id_to_function) | 95 const GrowableArray<const Function*>& inline_id_to_function, |
| 96 const GrowableArray<intptr_t>& caller_inline_id) |
| 93 : isolate_(Isolate::Current()), | 97 : isolate_(Isolate::Current()), |
| 94 assembler_(assembler), | 98 assembler_(assembler), |
| 95 parsed_function_(parsed_function), | 99 parsed_function_(parsed_function), |
| 96 flow_graph_(*flow_graph), | 100 flow_graph_(*flow_graph), |
| 97 block_order_(*flow_graph->CodegenBlockOrder(is_optimizing)), | 101 block_order_(*flow_graph->CodegenBlockOrder(is_optimizing)), |
| 98 current_block_(NULL), | 102 current_block_(NULL), |
| 99 exception_handlers_list_(NULL), | 103 exception_handlers_list_(NULL), |
| 100 pc_descriptors_list_(NULL), | 104 pc_descriptors_list_(NULL), |
| 101 stackmap_table_builder_( | 105 stackmap_table_builder_( |
| 102 is_optimizing ? new StackmapTableBuilder() : NULL), | 106 is_optimizing ? new StackmapTableBuilder() : NULL), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 120 list_class_(Class::ZoneHandle( | 124 list_class_(Class::ZoneHandle( |
| 121 Library::Handle(Library::CoreLibrary()). | 125 Library::Handle(Library::CoreLibrary()). |
| 122 LookupClass(Symbols::List()))), | 126 LookupClass(Symbols::List()))), |
| 123 parallel_move_resolver_(this), | 127 parallel_move_resolver_(this), |
| 124 pending_deoptimization_env_(NULL), | 128 pending_deoptimization_env_(NULL), |
| 125 entry_patch_pc_offset_(Code::kInvalidPc), | 129 entry_patch_pc_offset_(Code::kInvalidPc), |
| 126 patch_code_pc_offset_(Code::kInvalidPc), | 130 patch_code_pc_offset_(Code::kInvalidPc), |
| 127 lazy_deopt_pc_offset_(Code::kInvalidPc), | 131 lazy_deopt_pc_offset_(Code::kInvalidPc), |
| 128 deopt_id_to_ic_data_(NULL), | 132 deopt_id_to_ic_data_(NULL), |
| 129 inlined_code_intervals_(NULL), | 133 inlined_code_intervals_(NULL), |
| 130 inline_id_to_function_(inline_id_to_function) { | 134 inline_id_to_function_(inline_id_to_function), |
| 135 caller_inline_id_(caller_inline_id) { |
| 131 ASSERT(flow_graph->parsed_function().function().raw() == | 136 ASSERT(flow_graph->parsed_function().function().raw() == |
| 132 parsed_function.function().raw()); | 137 parsed_function.function().raw()); |
| 133 if (!is_optimizing) { | 138 if (!is_optimizing) { |
| 134 const intptr_t len = isolate()->deopt_id(); | 139 const intptr_t len = isolate()->deopt_id(); |
| 135 deopt_id_to_ic_data_ = new(isolate()) ZoneGrowableArray<const ICData*>(len); | 140 deopt_id_to_ic_data_ = new(isolate()) ZoneGrowableArray<const ICData*>(len); |
| 136 deopt_id_to_ic_data_->SetLength(len); | 141 deopt_id_to_ic_data_->SetLength(len); |
| 137 for (intptr_t i = 0; i < len; i++) { | 142 for (intptr_t i = 0; i < len; i++) { |
| 138 (*deopt_id_to_ic_data_)[i] = NULL; | 143 (*deopt_id_to_ic_data_)[i] = NULL; |
| 139 } | 144 } |
| 140 const Array& old_saved_icdata = Array::Handle(isolate(), | 145 const Array& old_saved_icdata = Array::Handle(isolate(), |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 } | 350 } |
| 346 } | 351 } |
| 347 } | 352 } |
| 348 } | 353 } |
| 349 | 354 |
| 350 | 355 |
| 351 // We collect intervals while generating code. | 356 // We collect intervals while generating code. |
| 352 struct IntervalStruct { | 357 struct IntervalStruct { |
| 353 // 'start' and 'end' are pc-offsets. | 358 // 'start' and 'end' are pc-offsets. |
| 354 intptr_t start; | 359 intptr_t start; |
| 355 intptr_t end; | |
| 356 intptr_t inlining_id; | 360 intptr_t inlining_id; |
| 357 IntervalStruct(intptr_t s, intptr_t e, intptr_t id) | 361 IntervalStruct(intptr_t s, intptr_t id) : start(s), inlining_id(id) {} |
| 358 : start(s), end(e), inlining_id(id) {} | 362 void Dump() { |
| 363 OS::Print("start: %" Px " id: %" Pd "", start, inlining_id); |
| 364 } |
| 359 }; | 365 }; |
| 360 | 366 |
| 361 | 367 |
| 362 void FlowGraphCompiler::VisitBlocks() { | 368 void FlowGraphCompiler::VisitBlocks() { |
| 363 CompactBlocks(); | 369 CompactBlocks(); |
| 364 const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL; | 370 const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL; |
| 365 if (Assembler::EmittingComments()) { | 371 if (Assembler::EmittingComments()) { |
| 366 // 'loop_headers' were cleared, recompute. | 372 // 'loop_headers' were cleared, recompute. |
| 367 loop_headers = flow_graph().ComputeLoops(); | 373 loop_headers = flow_graph().ComputeLoops(); |
| 368 ASSERT(loop_headers != NULL); | 374 ASSERT(loop_headers != NULL); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 387 | 393 |
| 388 entry->set_offset(assembler()->CodeSize()); | 394 entry->set_offset(assembler()->CodeSize()); |
| 389 entry->EmitNativeCode(this); | 395 entry->EmitNativeCode(this); |
| 390 // Compile all successors until an exit, branch, or a block entry. | 396 // Compile all successors until an exit, branch, or a block entry. |
| 391 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 397 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 392 Instruction* instr = it.Current(); | 398 Instruction* instr = it.Current(); |
| 393 // Compose intervals. | 399 // Compose intervals. |
| 394 if (instr->has_inlining_id() && is_optimizing()) { | 400 if (instr->has_inlining_id() && is_optimizing()) { |
| 395 if (prev_inlining_id != instr->inlining_id()) { | 401 if (prev_inlining_id != instr->inlining_id()) { |
| 396 intervals.Add(IntervalStruct(prev_offset, | 402 intervals.Add(IntervalStruct(prev_offset, |
| 397 assembler()->CodeSize(), | |
| 398 prev_inlining_id)); | 403 prev_inlining_id)); |
| 399 prev_offset = assembler()->CodeSize(); | 404 prev_offset = assembler()->CodeSize(); |
| 400 prev_inlining_id = instr->inlining_id(); | 405 prev_inlining_id = instr->inlining_id(); |
| 401 if (prev_inlining_id > max_inlining_id) { | 406 if (prev_inlining_id > max_inlining_id) { |
| 402 max_inlining_id = prev_inlining_id; | 407 max_inlining_id = prev_inlining_id; |
| 403 } | 408 } |
| 404 } | 409 } |
| 405 } | 410 } |
| 406 if (FLAG_code_comments || | 411 if (FLAG_code_comments || |
| 407 FLAG_disassemble || | 412 FLAG_disassemble || |
| 408 FLAG_disassemble_optimized) { | 413 FLAG_disassemble_optimized) { |
| 409 if (FLAG_source_lines) { | 414 if (FLAG_source_lines) { |
| 410 EmitSourceLine(instr); | 415 EmitSourceLine(instr); |
| 411 } | 416 } |
| 412 EmitComment(instr); | 417 EmitComment(instr); |
| 413 } | 418 } |
| 414 if (instr->IsParallelMove()) { | 419 if (instr->IsParallelMove()) { |
| 415 parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove()); | 420 parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove()); |
| 416 } else { | 421 } else { |
| 417 EmitInstructionPrologue(instr); | 422 EmitInstructionPrologue(instr); |
| 418 ASSERT(pending_deoptimization_env_ == NULL); | 423 ASSERT(pending_deoptimization_env_ == NULL); |
| 419 pending_deoptimization_env_ = instr->env(); | 424 pending_deoptimization_env_ = instr->env(); |
| 420 instr->EmitNativeCode(this); | 425 instr->EmitNativeCode(this); |
| 421 pending_deoptimization_env_ = NULL; | 426 pending_deoptimization_env_ = NULL; |
| 422 EmitInstructionEpilogue(instr); | 427 EmitInstructionEpilogue(instr); |
| 423 } | 428 } |
| 424 } | 429 } |
| 425 } | 430 } |
| 426 | 431 |
| 427 intervals.Add(IntervalStruct(prev_offset, assembler()->CodeSize(), | 432 if (inline_id_to_function_.length() > max_inlining_id + 1) { |
| 428 prev_inlining_id)); | 433 // TODO(srdjan): Some inlined function can disappear, |
| 429 // Note that ranges [start..end] must be monotonically increasing in | 434 // truncate 'inline_id_to_function_'. |
| 430 // 'intervals' array. | 435 } |
| 436 |
| 437 intervals.Add(IntervalStruct(prev_offset, prev_inlining_id)); |
| 431 inlined_code_intervals_ = &Array::ZoneHandle(Array::New( | 438 inlined_code_intervals_ = &Array::ZoneHandle(Array::New( |
| 432 (max_inlining_id + 1) * Code::kInlIntNumEntries, Heap::kOld)); | 439 intervals.length() * Code::kInlIntNumEntries, Heap::kOld)); |
| 433 | |
| 434 Smi& start_h = Smi::Handle(); | 440 Smi& start_h = Smi::Handle(); |
| 435 Smi& end_h = Smi::Handle(); | 441 Smi& caller_inline_id = Smi::Handle(); |
| 442 Smi& inline_id = Smi::Handle(); |
| 436 for (intptr_t i = 0; i < intervals.length(); i++) { | 443 for (intptr_t i = 0; i < intervals.length(); i++) { |
| 437 const intptr_t id = intervals[i].inlining_id; | 444 if (FLAG_trace_inlining_intervals && is_optimizing()) { |
| 438 end_h = Smi::New(intervals[i].end); | |
| 439 if (inlined_code_intervals_->At | |
| 440 (id * Code::kInlIntNumEntries + Code::kInlIntFunction) == | |
| 441 Object::null()) { | |
| 442 start_h = Smi::New(intervals[i].start); | |
| 443 inlined_code_intervals_->SetAt( | |
| 444 id * Code::kInlIntNumEntries + Code::kInlIntStart, start_h); | |
| 445 inlined_code_intervals_->SetAt( | |
| 446 id * Code::kInlIntNumEntries + Code::kInlIntEnd, end_h); | |
| 447 const Function* function = | 445 const Function* function = |
| 448 inline_id_to_function_.At(intervals[i].inlining_id); | 446 inline_id_to_function_.At(intervals[i].inlining_id); |
| 449 inlined_code_intervals_->SetAt( | 447 intervals[i].Dump(); |
| 450 id * Code::kInlIntNumEntries + Code::kInlIntFunction, *function); | 448 OS::Print(" %s parent %" Pd "\n", |
| 451 } else { | 449 function->ToQualifiedCString(), |
| 452 // Check for monotonic increase. | 450 caller_inline_id_[intervals[i].inlining_id]); |
| 453 #if defined(DEBUG) | 451 } |
| 454 Smi& temp = Smi::Handle(); | 452 const intptr_t id = intervals[i].inlining_id; |
| 455 temp ^= inlined_code_intervals_->At( | 453 start_h = Smi::New(intervals[i].start); |
| 456 id * Code::kInlIntNumEntries + Code::kInlIntStart); | 454 inline_id = Smi::New(id); |
| 457 start_h = Smi::New(intervals[i].start); | 455 caller_inline_id = Smi::New(caller_inline_id_[intervals[i].inlining_id]); |
| 458 ASSERT(temp.Value() <= start_h.Value()); | 456 |
| 459 temp ^= inlined_code_intervals_->At( | 457 const intptr_t p = i * Code::kInlIntNumEntries; |
| 460 id * Code::kInlIntNumEntries + Code::kInlIntEnd); | 458 inlined_code_intervals_->SetAt(p + Code::kInlIntStart, start_h); |
| 461 ASSERT(temp.Value() <= end_h.Value()); | 459 inlined_code_intervals_->SetAt(p + Code::kInlIntInliningId, inline_id); |
| 462 const Function* function = | 460 inlined_code_intervals_->SetAt(p + Code::kInlIntCallerId, caller_inline_id); |
| 463 inline_id_to_function_.At(intervals[i].inlining_id); | 461 } |
| 464 Function& f = Function::Handle(); | 462 set_current_block(NULL); |
| 465 f ^= inlined_code_intervals_->At( | 463 if (FLAG_trace_inlining_intervals && is_optimizing()) { |
| 466 id * Code::kInlIntNumEntries + Code::kInlIntFunction); | 464 OS::Print("Intervals:\n"); |
| 467 ASSERT(function->raw() == f.raw()); | 465 Smi& temp = Smi::Handle(); |
| 468 #endif | 466 for (intptr_t i = 0; i < inlined_code_intervals_->Length(); |
| 469 inlined_code_intervals_->SetAt( | 467 i += Code::kInlIntNumEntries) { |
| 470 id * Code::kInlIntNumEntries + Code::kInlIntEnd, end_h); | 468 temp ^= inlined_code_intervals_->At(i + Code::kInlIntStart); |
| 469 ASSERT(!temp.IsNull()); |
| 470 OS::Print("% " Pd " start: %" Px " ", i, temp.Value()); |
| 471 temp ^= inlined_code_intervals_->At(i + Code::kInlIntInliningId); |
| 472 OS::Print("inl-id: %" Pd " ", temp.Value()); |
| 473 temp ^= inlined_code_intervals_->At(i + Code::kInlIntCallerId); |
| 474 OS::Print("caller-id: %" Pd " \n", temp.Value()); |
| 471 } | 475 } |
| 472 } | 476 } |
| 473 set_current_block(NULL); | |
| 474 } | 477 } |
| 475 | 478 |
| 476 | 479 |
| 477 void FlowGraphCompiler::Bailout(const char* reason) { | 480 void FlowGraphCompiler::Bailout(const char* reason) { |
| 478 const Function& function = parsed_function_.function(); | 481 const Function& function = parsed_function_.function(); |
| 479 Report::MessageF(Report::kBailout, | 482 Report::MessageF(Report::kBailout, |
| 480 Script::Handle(function.script()), | 483 Script::Handle(function.script()), |
| 481 function.token_pos(), | 484 function.token_pos(), |
| 482 "FlowGraphCompiler Bailout: %s %s", | 485 "FlowGraphCompiler Bailout: %s %s", |
| 483 String::Handle(function.name()).ToCString(), | 486 String::Handle(function.name()).ToCString(), |
| (...skipping 1089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1573 return int32x4_class(); | 1576 return int32x4_class(); |
| 1574 case kUnboxedMint: | 1577 case kUnboxedMint: |
| 1575 return mint_class(); | 1578 return mint_class(); |
| 1576 default: | 1579 default: |
| 1577 UNREACHABLE(); | 1580 UNREACHABLE(); |
| 1578 return Class::ZoneHandle(); | 1581 return Class::ZoneHandle(); |
| 1579 } | 1582 } |
| 1580 } | 1583 } |
| 1581 | 1584 |
| 1582 | 1585 |
| 1586 RawArray* FlowGraphCompiler::InliningIdToFunction() const { |
| 1587 const Array& res = Array::Handle( |
| 1588 Array::New(inline_id_to_function_.length(), Heap::kOld)); |
| 1589 for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) { |
| 1590 res.SetAt(i, *inline_id_to_function_[i]); |
| 1591 } |
| 1592 return res.raw(); |
| 1593 } |
| 1594 |
| 1595 |
| 1583 } // namespace dart | 1596 } // namespace dart |
| OLD | NEW |