| 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/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| 11 #include "vm/compiler_stats.h" | 11 #include "vm/compiler_stats.h" |
| 12 #include "vm/debugger.h" | |
| 13 #include "vm/il_printer.h" | 12 #include "vm/il_printer.h" |
| 14 #include "vm/intrinsifier.h" | |
| 15 #include "vm/locations.h" | 13 #include "vm/locations.h" |
| 16 #include "vm/longjump.h" | |
| 17 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
| 18 | 15 |
| 19 namespace dart { | 16 namespace dart { |
| 20 | 17 |
| 21 DECLARE_FLAG(bool, code_comments); | 18 DECLARE_FLAG(bool, code_comments); |
| 22 DECLARE_FLAG(bool, compiler_stats); | 19 DECLARE_FLAG(bool, compiler_stats); |
| 23 DECLARE_FLAG(bool, enable_type_checks); | 20 DECLARE_FLAG(bool, enable_type_checks); |
| 24 DECLARE_FLAG(bool, intrinsify); | |
| 25 DECLARE_FLAG(int, optimization_counter_threshold); | |
| 26 DECLARE_FLAG(bool, print_ast); | 21 DECLARE_FLAG(bool, print_ast); |
| 27 DECLARE_FLAG(bool, print_scopes); | 22 DECLARE_FLAG(bool, print_scopes); |
| 28 DECLARE_FLAG(bool, report_usage_count); | |
| 29 DECLARE_FLAG(bool, trace_functions); | 23 DECLARE_FLAG(bool, trace_functions); |
| 30 | 24 |
| 31 | 25 |
| 32 void DeoptimizationStub::GenerateCode(FlowGraphCompilerShared* compiler) { | 26 void DeoptimizationStub::GenerateCode(FlowGraphCompilerShared* compiler) { |
| 33 Assembler* assem = compiler->assembler(); | 27 Assembler* assem = compiler->assembler(); |
| 34 #define __ assem-> | 28 #define __ assem-> |
| 35 __ Comment("Deopt stub for id %d", deopt_id_); | 29 __ Comment("Deopt stub for id %d", deopt_id_); |
| 36 __ Bind(entry_label()); | 30 __ Bind(entry_label()); |
| 37 for (intptr_t i = 0; i < registers_.length(); i++) { | 31 for (intptr_t i = 0; i < registers_.length(); i++) { |
| 38 if (registers_[i] != kNoRegister) { | 32 if (registers_[i] != kNoRegister) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 53 Assembler* assembler, | 47 Assembler* assembler, |
| 54 const ParsedFunction& parsed_function, | 48 const ParsedFunction& parsed_function, |
| 55 const GrowableArray<BlockEntryInstr*>& block_order, | 49 const GrowableArray<BlockEntryInstr*>& block_order, |
| 56 bool is_optimizing) | 50 bool is_optimizing) |
| 57 : FlowGraphCompilerShared(assembler, | 51 : FlowGraphCompilerShared(assembler, |
| 58 parsed_function, | 52 parsed_function, |
| 59 block_order, | 53 block_order, |
| 60 is_optimizing) {} | 54 is_optimizing) {} |
| 61 | 55 |
| 62 | 56 |
| 63 void FlowGraphCompiler::FinalizeComments(const Code& code) { | |
| 64 code.set_comments(assembler()->GetCodeComments()); | |
| 65 } | |
| 66 | |
| 67 | |
| 68 void FlowGraphCompiler::Bailout(const char* reason) { | |
| 69 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; | |
| 70 const char* function_name = parsed_function().function().ToCString(); | |
| 71 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | |
| 72 char* chars = reinterpret_cast<char*>( | |
| 73 Isolate::Current()->current_zone()->Allocate(len)); | |
| 74 OS::SNPrint(chars, len, kFormat, function_name, reason); | |
| 75 const Error& error = Error::Handle( | |
| 76 LanguageError::New(String::Handle(String::New(chars)))); | |
| 77 Isolate::Current()->long_jump_base()->Jump(1, error); | |
| 78 } | |
| 79 | |
| 80 | |
| 81 #define __ assembler()-> | 57 #define __ assembler()-> |
| 82 | 58 |
| 83 void FlowGraphCompiler::IntrinsifyGetter() { | 59 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 84 // TOS: return address. | 60 // TOS: return address. |
| 85 // +1 : receiver. | 61 // +1 : receiver. |
| 86 // Sequence node has one return node, its input is load field node. | 62 // Sequence node has one return node, its input is load field node. |
| 87 const SequenceNode& sequence_node = *parsed_function().node_sequence(); | |
| 88 ASSERT(sequence_node.length() == 1); | |
| 89 ASSERT(sequence_node.NodeAt(0)->IsReturnNode()); | |
| 90 const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode(); | |
| 91 ASSERT(return_node.value()->IsLoadInstanceFieldNode()); | |
| 92 const LoadInstanceFieldNode& load_node = | |
| 93 *return_node.value()->AsLoadInstanceFieldNode(); | |
| 94 __ movl(EAX, Address(ESP, 1 * kWordSize)); | 63 __ movl(EAX, Address(ESP, 1 * kWordSize)); |
| 95 __ movl(EAX, FieldAddress(EAX, load_node.field().Offset())); | 64 __ movl(EAX, FieldAddress(EAX, offset)); |
| 96 __ ret(); | 65 __ ret(); |
| 97 } | 66 } |
| 98 | 67 |
| 99 | 68 |
| 100 void FlowGraphCompiler::IntrinsifySetter() { | 69 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 101 // TOS: return address. | 70 // TOS: return address. |
| 102 // +1 : value | 71 // +1 : value |
| 103 // +2 : receiver. | 72 // +2 : receiver. |
| 104 // Sequence node has one store node and one return NULL node. | |
| 105 const SequenceNode& sequence_node = *parsed_function().node_sequence(); | |
| 106 ASSERT(sequence_node.length() == 2); | |
| 107 ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode()); | |
| 108 ASSERT(sequence_node.NodeAt(1)->IsReturnNode()); | |
| 109 const StoreInstanceFieldNode& store_node = | |
| 110 *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode(); | |
| 111 __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver. | 73 __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver. |
| 112 __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value. | 74 __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value. |
| 113 __ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX); | 75 __ StoreIntoObject(EAX, FieldAddress(EAX, offset), EBX); |
| 114 const Immediate raw_null = | 76 const Immediate raw_null = |
| 115 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 77 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 116 __ movl(EAX, raw_null); | 78 __ movl(EAX, raw_null); |
| 117 __ ret(); | 79 __ ret(); |
| 118 } | 80 } |
| 119 | 81 |
| 120 | 82 |
| 121 bool FlowGraphCompiler::CanOptimize() { | |
| 122 return | |
| 123 !FLAG_report_usage_count && | |
| 124 (FLAG_optimization_counter_threshold >= 0) && | |
| 125 !Isolate::Current()->debugger()->IsActive(); | |
| 126 } | |
| 127 | |
| 128 | |
| 129 // Returns 'true' if code generation for this function is complete, i.e., | |
| 130 // no fall-through to regular code is needed. | |
| 131 bool FlowGraphCompiler::TryIntrinsify() { | |
| 132 if (!CanOptimize()) return false; | |
| 133 // Intrinsification skips arguments checks, therefore disable if in checked | |
| 134 // mode. | |
| 135 if (FLAG_intrinsify && !FLAG_trace_functions && !FLAG_enable_type_checks) { | |
| 136 if ((parsed_function().function().kind() == RawFunction::kImplicitGetter)) { | |
| 137 IntrinsifyGetter(); | |
| 138 return true; | |
| 139 } | |
| 140 if ((parsed_function().function().kind() == RawFunction::kImplicitSetter)) { | |
| 141 IntrinsifySetter(); | |
| 142 return true; | |
| 143 } | |
| 144 } | |
| 145 // Even if an intrinsified version of the function was successfully | |
| 146 // generated, it may fall through to the non-intrinsified method body. | |
| 147 if (!FLAG_trace_functions) { | |
| 148 return Intrinsifier::Intrinsify(parsed_function().function(), assembler()); | |
| 149 } | |
| 150 return false; | |
| 151 } | |
| 152 | |
| 153 | |
| 154 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, | 83 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, |
| 155 intptr_t token_index, | 84 intptr_t token_index, |
| 156 intptr_t try_index, | 85 intptr_t try_index, |
| 157 const RuntimeEntry& entry) { | 86 const RuntimeEntry& entry) { |
| 158 __ CallRuntime(entry); | 87 __ CallRuntime(entry); |
| 159 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); | 88 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); |
| 160 } | 89 } |
| 161 | 90 |
| 162 | 91 |
| 163 void FlowGraphCompiler::CopyParameters() { | 92 void FlowGraphCompiler::CopyParameters() { |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 // at entry point. | 366 // at entry point. |
| 438 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, | 367 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, |
| 439 assembler()->CodeSize(), | 368 assembler()->CodeSize(), |
| 440 AstNode::kNoId, | 369 AstNode::kNoId, |
| 441 0, | 370 0, |
| 442 -1); | 371 -1); |
| 443 __ jmp(&StubCode::FixCallersTargetLabel()); | 372 __ jmp(&StubCode::FixCallersTargetLabel()); |
| 444 } | 373 } |
| 445 | 374 |
| 446 | 375 |
| 447 void FlowGraphCompiler::EmitInstanceCall(intptr_t cid, | 376 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 448 intptr_t token_index, | 377 const ICData& ic_data, |
| 449 intptr_t try_index, | 378 const Array& arguments_descriptor, |
| 450 const String& function_name, | 379 intptr_t argument_count) { |
| 451 intptr_t argument_count, | |
| 452 const Array& argument_names, | |
| 453 intptr_t checked_argument_count) { | |
| 454 ICData& ic_data = ICData::ZoneHandle(ICData::New(parsed_function().function(), | |
| 455 function_name, | |
| 456 cid, | |
| 457 checked_argument_count)); | |
| 458 const Array& arguments_descriptor = | |
| 459 CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); | |
| 460 __ LoadObject(ECX, ic_data); | 380 __ LoadObject(ECX, ic_data); |
| 461 __ LoadObject(EDX, arguments_descriptor); | 381 __ LoadObject(EDX, arguments_descriptor); |
| 462 | 382 |
| 463 uword label_address = 0; | 383 __ call(target_label); |
| 464 switch (checked_argument_count) { | 384 const intptr_t descr_offset = assembler()->CodeSize(); |
| 465 case 1: | |
| 466 label_address = StubCode::OneArgCheckInlineCacheEntryPoint(); | |
| 467 break; | |
| 468 case 2: | |
| 469 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); | |
| 470 break; | |
| 471 default: | |
| 472 UNIMPLEMENTED(); | |
| 473 } | |
| 474 ExternalLabel target_label("InlineCache", label_address); | |
| 475 __ call(&target_label); | |
| 476 AddCurrentDescriptor(PcDescriptors::kIcCall, cid, token_index, try_index); | |
| 477 __ Drop(argument_count); | 385 __ Drop(argument_count); |
| 386 return descr_offset; |
| 478 } | 387 } |
| 479 | 388 |
| 480 | 389 |
| 481 void FlowGraphCompiler::EmitStaticCall(intptr_t token_index, | 390 intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function, |
| 482 intptr_t try_index, | 391 const Array& arguments_descriptor, |
| 483 const Function& function, | 392 intptr_t argument_count) { |
| 484 intptr_t argument_count, | |
| 485 const Array& argument_names) { | |
| 486 const Array& arguments_descriptor = | |
| 487 CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); | |
| 488 __ LoadObject(ECX, function); | 393 __ LoadObject(ECX, function); |
| 489 __ LoadObject(EDX, arguments_descriptor); | 394 __ LoadObject(EDX, arguments_descriptor); |
| 490 | 395 __ call(&StubCode::CallStaticFunctionLabel()); |
| 491 GenerateCall(token_index, | 396 const intptr_t descr_offset = assembler()->CodeSize(); |
| 492 try_index, | |
| 493 &StubCode::CallStaticFunctionLabel(), | |
| 494 PcDescriptors::kFuncCall); | |
| 495 __ Drop(argument_count); | 397 __ Drop(argument_count); |
| 398 return descr_offset; |
| 496 } | 399 } |
| 497 | 400 |
| 498 | 401 |
| 499 void FlowGraphCompiler::GenerateCall(intptr_t token_index, | 402 void FlowGraphCompiler::GenerateCall(intptr_t token_index, |
| 500 intptr_t try_index, | 403 intptr_t try_index, |
| 501 const ExternalLabel* label, | 404 const ExternalLabel* label, |
| 502 PcDescriptors::Kind kind) { | 405 PcDescriptors::Kind kind) { |
| 503 __ call(label); | 406 __ call(label); |
| 504 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); | 407 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); |
| 505 } | 408 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 } | 468 } |
| 566 } | 469 } |
| 567 } | 470 } |
| 568 } | 471 } |
| 569 | 472 |
| 570 #undef __ | 473 #undef __ |
| 571 | 474 |
| 572 } // namespace dart | 475 } // namespace dart |
| 573 | 476 |
| 574 #endif // defined TARGET_ARCH_IA32 | 477 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |