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