| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
| 12 #include "vm/code_descriptors.h" | 12 #include "vm/code_descriptors.h" |
| 13 #include "vm/code_generator.h" | 13 #include "vm/code_generator.h" |
| 14 #include "vm/debugger.h" | |
| 15 #include "vm/disassembler.h" | 14 #include "vm/disassembler.h" |
| 16 #include "vm/il_printer.h" | 15 #include "vm/il_printer.h" |
| 17 #include "vm/intrinsifier.h" | |
| 18 #include "vm/locations.h" | 16 #include "vm/locations.h" |
| 19 #include "vm/longjump.h" | |
| 20 #include "vm/object_store.h" | 17 #include "vm/object_store.h" |
| 21 #include "vm/parser.h" | 18 #include "vm/parser.h" |
| 22 #include "vm/stub_code.h" | 19 #include "vm/stub_code.h" |
| 23 | 20 |
| 24 namespace dart { | 21 namespace dart { |
| 25 | 22 |
| 26 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); | 23 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); |
| 27 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); | 24 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); |
| 28 DECLARE_FLAG(bool, enable_type_checks); | 25 DECLARE_FLAG(bool, enable_type_checks); |
| 29 DECLARE_FLAG(bool, intrinsify); | |
| 30 DECLARE_FLAG(int, optimization_counter_threshold); | |
| 31 DECLARE_FLAG(bool, print_ast); | 26 DECLARE_FLAG(bool, print_ast); |
| 32 DECLARE_FLAG(bool, report_usage_count); | |
| 33 DECLARE_FLAG(bool, code_comments); | 27 DECLARE_FLAG(bool, code_comments); |
| 34 | 28 |
| 35 | 29 |
| 36 void DeoptimizationStub::GenerateCode(FlowGraphCompilerShared* compiler) { | 30 void DeoptimizationStub::GenerateCode(FlowGraphCompilerShared* compiler) { |
| 37 Assembler* assem = compiler->assembler(); | 31 Assembler* assem = compiler->assembler(); |
| 38 #define __ assem-> | 32 #define __ assem-> |
| 39 __ Comment("Deopt stub for id %d", deopt_id_); | 33 __ Comment("Deopt stub for id %d", deopt_id_); |
| 40 __ Bind(entry_label()); | 34 __ Bind(entry_label()); |
| 41 for (intptr_t i = 0; i < registers_.length(); i++) { | 35 for (intptr_t i = 0; i < registers_.length(); i++) { |
| 42 if (registers_[i] != kNoRegister) { | 36 if (registers_[i] != kNoRegister) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 56 FlowGraphCompiler::FlowGraphCompiler( | 50 FlowGraphCompiler::FlowGraphCompiler( |
| 57 Assembler* assembler, | 51 Assembler* assembler, |
| 58 const ParsedFunction& parsed_function, | 52 const ParsedFunction& parsed_function, |
| 59 const GrowableArray<BlockEntryInstr*>& block_order, | 53 const GrowableArray<BlockEntryInstr*>& block_order, |
| 60 bool is_optimizing) | 54 bool is_optimizing) |
| 61 : FlowGraphCompilerShared(assembler, | 55 : FlowGraphCompilerShared(assembler, |
| 62 parsed_function, | 56 parsed_function, |
| 63 block_order, | 57 block_order, |
| 64 is_optimizing) {} | 58 is_optimizing) {} |
| 65 | 59 |
| 66 | |
| 67 void FlowGraphCompiler::Bailout(const char* reason) { | |
| 68 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; | |
| 69 const char* function_name = parsed_function().function().ToCString(); | |
| 70 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | |
| 71 char* chars = reinterpret_cast<char*>( | |
| 72 Isolate::Current()->current_zone()->Allocate(len)); | |
| 73 OS::SNPrint(chars, len, kFormat, function_name, reason); | |
| 74 const Error& error = Error::Handle( | |
| 75 LanguageError::New(String::Handle(String::New(chars)))); | |
| 76 Isolate::Current()->long_jump_base()->Jump(1, error); | |
| 77 } | |
| 78 | |
| 79 | |
| 80 #define __ assembler()-> | 60 #define __ assembler()-> |
| 81 | 61 |
| 82 | 62 |
| 83 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 63 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 84 // type test is conclusive, otherwise fallthrough if a type test could not | 64 // type test is conclusive, otherwise fallthrough if a type test could not |
| 85 // be completed. | 65 // be completed. |
| 86 // RAX: instance (must survive), | 66 // RAX: instance (must survive), |
| 87 RawSubtypeTestCache* | 67 RawSubtypeTestCache* |
| 88 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 68 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 89 intptr_t cid, | 69 intptr_t cid, |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 } else { | 533 } else { |
| 554 __ LoadObject(dst, value->AsConstant()->value()); | 534 __ LoadObject(dst, value->AsConstant()->value()); |
| 555 } | 535 } |
| 556 } else { | 536 } else { |
| 557 ASSERT(value->IsUse()); | 537 ASSERT(value->IsUse()); |
| 558 __ popq(dst); | 538 __ popq(dst); |
| 559 } | 539 } |
| 560 } | 540 } |
| 561 | 541 |
| 562 | 542 |
| 563 void FlowGraphCompiler::EmitInstanceCall(intptr_t cid, | 543 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 564 intptr_t token_index, | 544 const ICData& ic_data, |
| 565 intptr_t try_index, | 545 const Array& arguments_descriptor, |
| 566 const String& function_name, | 546 intptr_t argument_count) { |
| 567 intptr_t argument_count, | |
| 568 const Array& argument_names, | |
| 569 intptr_t checked_argument_count) { | |
| 570 ICData& ic_data = | |
| 571 ICData::ZoneHandle(ICData::New(parsed_function().function(), | |
| 572 function_name, | |
| 573 cid, | |
| 574 checked_argument_count)); | |
| 575 const Array& arguments_descriptor = | |
| 576 CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); | |
| 577 __ LoadObject(RBX, ic_data); | 547 __ LoadObject(RBX, ic_data); |
| 578 __ LoadObject(R10, arguments_descriptor); | 548 __ LoadObject(R10, arguments_descriptor); |
| 579 | 549 |
| 580 uword label_address = 0; | 550 __ call(target_label); |
| 581 switch (checked_argument_count) { | 551 const intptr_t descr_offset = assembler()->CodeSize(); |
| 582 case 1: | |
| 583 label_address = StubCode::OneArgCheckInlineCacheEntryPoint(); | |
| 584 break; | |
| 585 case 2: | |
| 586 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); | |
| 587 break; | |
| 588 default: | |
| 589 UNIMPLEMENTED(); | |
| 590 } | |
| 591 ExternalLabel target_label("InlineCache", label_address); | |
| 592 __ call(&target_label); | |
| 593 AddCurrentDescriptor(PcDescriptors::kIcCall, cid, token_index, try_index); | |
| 594 __ Drop(argument_count); | 552 __ Drop(argument_count); |
| 553 return descr_offset; |
| 554 } |
| 555 |
| 556 intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function, |
| 557 const Array& arguments_descriptor, |
| 558 intptr_t argument_count) { |
| 559 __ LoadObject(RBX, function); |
| 560 __ LoadObject(R10, arguments_descriptor); |
| 561 __ call(&StubCode::CallStaticFunctionLabel()); |
| 562 const intptr_t descr_offset = assembler()->CodeSize(); |
| 563 __ Drop(argument_count); |
| 564 return descr_offset; |
| 595 } | 565 } |
| 596 | 566 |
| 597 | 567 |
| 598 void FlowGraphCompiler::EmitStaticCall(intptr_t token_index, | |
| 599 intptr_t try_index, | |
| 600 const Function& function, | |
| 601 intptr_t argument_count, | |
| 602 const Array& argument_names) { | |
| 603 const Array& arguments_descriptor = | |
| 604 CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); | |
| 605 __ LoadObject(RBX, function); | |
| 606 __ LoadObject(R10, arguments_descriptor); | |
| 607 | |
| 608 GenerateCall(token_index, | |
| 609 try_index, | |
| 610 &StubCode::CallStaticFunctionLabel(), | |
| 611 PcDescriptors::kFuncCall); | |
| 612 __ Drop(argument_count); | |
| 613 } | |
| 614 | |
| 615 | |
| 616 // Optimize instanceof type test by adding inlined tests for: | 568 // Optimize instanceof type test by adding inlined tests for: |
| 617 // - NULL -> return false. | 569 // - NULL -> return false. |
| 618 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 570 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 619 // - Class equality (only if class is not parameterized). | 571 // - Class equality (only if class is not parameterized). |
| 620 // Inputs: | 572 // Inputs: |
| 621 // - RAX: object. | 573 // - RAX: object. |
| 622 // - RDX: instantiator type arguments or raw_null. | 574 // - RDX: instantiator type arguments or raw_null. |
| 623 // - RCX: instantiator or raw_null. | 575 // - RCX: instantiator or raw_null. |
| 624 // Destroys RCX and RDX. | 576 // Destroys RCX and RDX. |
| 625 // Returns: | 577 // Returns: |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 890 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 939 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); | 891 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); |
| 940 __ Bind(&null_args_loop); | 892 __ Bind(&null_args_loop); |
| 941 __ movq(original_argument_addr, raw_null); | 893 __ movq(original_argument_addr, raw_null); |
| 942 __ Bind(&null_args_loop_condition); | 894 __ Bind(&null_args_loop_condition); |
| 943 __ decq(RCX); | 895 __ decq(RCX); |
| 944 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 896 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 945 } | 897 } |
| 946 | 898 |
| 947 | 899 |
| 948 bool FlowGraphCompiler::CanOptimize() { | 900 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 949 return | |
| 950 !FLAG_report_usage_count && | |
| 951 (FLAG_optimization_counter_threshold >= 0) && | |
| 952 !Isolate::Current()->debugger()->IsActive(); | |
| 953 } | |
| 954 | |
| 955 | |
| 956 void FlowGraphCompiler::IntrinsifyGetter() { | |
| 957 // TOS: return address. | 901 // TOS: return address. |
| 958 // +1 : receiver. | 902 // +1 : receiver. |
| 959 // Sequence node has one return node, its input is load field node. | 903 // Sequence node has one return node, its input is load field node. |
| 960 const SequenceNode& sequence_node = *parsed_function().node_sequence(); | |
| 961 ASSERT(sequence_node.length() == 1); | |
| 962 ASSERT(sequence_node.NodeAt(0)->IsReturnNode()); | |
| 963 const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode(); | |
| 964 ASSERT(return_node.value()->IsLoadInstanceFieldNode()); | |
| 965 const LoadInstanceFieldNode& load_node = | |
| 966 *return_node.value()->AsLoadInstanceFieldNode(); | |
| 967 __ movq(RAX, Address(RSP, 1 * kWordSize)); | 904 __ movq(RAX, Address(RSP, 1 * kWordSize)); |
| 968 __ movq(RAX, FieldAddress(RAX, load_node.field().Offset())); | 905 __ movq(RAX, FieldAddress(RAX, offset)); |
| 969 __ ret(); | 906 __ ret(); |
| 970 } | 907 } |
| 971 | 908 |
| 972 | 909 |
| 973 void FlowGraphCompiler::IntrinsifySetter() { | 910 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 974 // TOS: return address. | 911 // TOS: return address. |
| 975 // +1 : value | 912 // +1 : value |
| 976 // +2 : receiver. | 913 // +2 : receiver. |
| 977 // Sequence node has one store node and one return NULL node. | 914 // Sequence node has one store node and one return NULL node. |
| 978 const SequenceNode& sequence_node = *parsed_function().node_sequence(); | |
| 979 ASSERT(sequence_node.length() == 2); | |
| 980 ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode()); | |
| 981 ASSERT(sequence_node.NodeAt(1)->IsReturnNode()); | |
| 982 const StoreInstanceFieldNode& store_node = | |
| 983 *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode(); | |
| 984 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. | 915 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. |
| 985 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. | 916 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. |
| 986 __ StoreIntoObject(RAX, FieldAddress(RAX, store_node.field().Offset()), RBX); | 917 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); |
| 987 const Immediate raw_null = | 918 const Immediate raw_null = |
| 988 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 919 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 989 __ movq(RAX, raw_null); | 920 __ movq(RAX, raw_null); |
| 990 __ ret(); | 921 __ ret(); |
| 991 } | 922 } |
| 992 | 923 |
| 993 | 924 |
| 994 // Returns 'true' if code generation for this function is complete, i.e., | |
| 995 // no fall-through to regular code is needed. | |
| 996 bool FlowGraphCompiler::TryIntrinsify() { | |
| 997 if (!CanOptimize()) return false; | |
| 998 // Intrinsification skips arguments checks, therefore disable if in checked | |
| 999 // mode. | |
| 1000 if (FLAG_intrinsify && !FLAG_trace_functions && !FLAG_enable_type_checks) { | |
| 1001 if ((parsed_function().function().kind() == RawFunction::kImplicitGetter)) { | |
| 1002 IntrinsifyGetter(); | |
| 1003 return true; | |
| 1004 } | |
| 1005 if ((parsed_function().function().kind() == RawFunction::kImplicitSetter)) { | |
| 1006 IntrinsifySetter(); | |
| 1007 return true; | |
| 1008 } | |
| 1009 } | |
| 1010 // Even if an intrinsified version of the function was successfully | |
| 1011 // generated, it may fall through to the non-intrinsified method body. | |
| 1012 if (!FLAG_trace_functions) { | |
| 1013 return Intrinsifier::Intrinsify(parsed_function().function(), assembler()); | |
| 1014 } | |
| 1015 return false; | |
| 1016 } | |
| 1017 | |
| 1018 | |
| 1019 void FlowGraphCompiler::CompileGraph() { | 925 void FlowGraphCompiler::CompileGraph() { |
| 1020 InitCompiler(); | 926 InitCompiler(); |
| 1021 if (TryIntrinsify()) { | 927 if (TryIntrinsify()) { |
| 1022 // Make it patchable: code must have a minimum code size, nop(2) increases | 928 // Make it patchable: code must have a minimum code size, nop(2) increases |
| 1023 // the minimum code size appropriately. | 929 // the minimum code size appropriately. |
| 1024 __ nop(2); | 930 __ nop(2); |
| 1025 __ int3(); | 931 __ int3(); |
| 1026 __ jmp(&StubCode::FixCallersTargetLabel()); | 932 __ jmp(&StubCode::FixCallersTargetLabel()); |
| 1027 return; | 933 return; |
| 1028 } | 934 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 | 1029 |
| 1124 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, | 1030 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, |
| 1125 intptr_t token_index, | 1031 intptr_t token_index, |
| 1126 intptr_t try_index, | 1032 intptr_t try_index, |
| 1127 const RuntimeEntry& entry) { | 1033 const RuntimeEntry& entry) { |
| 1128 __ CallRuntime(entry); | 1034 __ CallRuntime(entry); |
| 1129 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); | 1035 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); |
| 1130 } | 1036 } |
| 1131 | 1037 |
| 1132 | 1038 |
| 1133 void FlowGraphCompiler::FinalizeComments(const Code& code) { | |
| 1134 code.set_comments(assembler()->GetCodeComments()); | |
| 1135 } | |
| 1136 | |
| 1137 #undef __ | 1039 #undef __ |
| 1138 | 1040 |
| 1139 } // namespace dart | 1041 } // namespace dart |
| 1140 | 1042 |
| 1141 #endif // defined TARGET_ARCH_X64 | 1043 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |