| 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_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 "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 | 154 |
| 155 | 155 |
| 156 #define __ assembler()-> | 156 #define __ assembler()-> |
| 157 | 157 |
| 158 | 158 |
| 159 // Fall through if bool_register contains null. | 159 // Fall through if bool_register contains null. |
| 160 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 160 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 161 Label* is_true, | 161 Label* is_true, |
| 162 Label* is_false) { | 162 Label* is_false) { |
| 163 Label fall_through; | 163 Label fall_through; |
| 164 __ CompareObject(bool_register, Object::Handle()); | 164 __ CompareObject(bool_register, Object::null_object()); |
| 165 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 165 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 166 __ CompareObject(bool_register, Bool::True()); | 166 __ CompareObject(bool_register, Bool::True()); |
| 167 __ j(EQUAL, is_true); | 167 __ j(EQUAL, is_true); |
| 168 __ jmp(is_false); | 168 __ jmp(is_false); |
| 169 __ Bind(&fall_through); | 169 __ Bind(&fall_through); |
| 170 } | 170 } |
| 171 | 171 |
| 172 | 172 |
| 173 // Clobbers RCX. | 173 // Clobbers RCX. |
| 174 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 174 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 175 TypeTestStubKind test_kind, | 175 TypeTestStubKind test_kind, |
| 176 Register instance_reg, | 176 Register instance_reg, |
| 177 Register type_arguments_reg, | 177 Register type_arguments_reg, |
| 178 Register temp_reg, | 178 Register temp_reg, |
| 179 Label* is_instance_lbl, | 179 Label* is_instance_lbl, |
| 180 Label* is_not_instance_lbl) { | 180 Label* is_not_instance_lbl) { |
| 181 const SubtypeTestCache& type_test_cache = | 181 const SubtypeTestCache& type_test_cache = |
| 182 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 182 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 183 __ LoadObject(temp_reg, type_test_cache, PP); | 183 __ LoadObject(temp_reg, type_test_cache, PP); |
| 184 __ pushq(temp_reg); // Subtype test cache. | 184 __ pushq(temp_reg); // Subtype test cache. |
| 185 __ pushq(instance_reg); // Instance. | 185 __ pushq(instance_reg); // Instance. |
| 186 if (test_kind == kTestTypeOneArg) { | 186 if (test_kind == kTestTypeOneArg) { |
| 187 ASSERT(type_arguments_reg == kNoRegister); | 187 ASSERT(type_arguments_reg == kNoRegister); |
| 188 __ PushObject(Object::Handle()); | 188 __ PushObject(Object::null_object()); |
| 189 __ Call(&StubCode::Subtype1TestCacheLabel(), PP); | 189 __ Call(&StubCode::Subtype1TestCacheLabel(), PP); |
| 190 } else if (test_kind == kTestTypeTwoArgs) { | 190 } else if (test_kind == kTestTypeTwoArgs) { |
| 191 ASSERT(type_arguments_reg == kNoRegister); | 191 ASSERT(type_arguments_reg == kNoRegister); |
| 192 __ PushObject(Object::Handle()); | 192 __ PushObject(Object::null_object()); |
| 193 __ Call(&StubCode::Subtype2TestCacheLabel(), PP); | 193 __ Call(&StubCode::Subtype2TestCacheLabel(), PP); |
| 194 } else if (test_kind == kTestTypeThreeArgs) { | 194 } else if (test_kind == kTestTypeThreeArgs) { |
| 195 __ pushq(type_arguments_reg); | 195 __ pushq(type_arguments_reg); |
| 196 __ Call(&StubCode::Subtype3TestCacheLabel(), PP); | 196 __ Call(&StubCode::Subtype3TestCacheLabel(), PP); |
| 197 } else { | 197 } else { |
| 198 UNREACHABLE(); | 198 UNREACHABLE(); |
| 199 } | 199 } |
| 200 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. | 200 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 201 ASSERT(instance_reg != RCX); | 201 ASSERT(instance_reg != RCX); |
| 202 ASSERT(temp_reg != RCX); | 202 ASSERT(temp_reg != RCX); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 if (type.IsBoolType()) { | 333 if (type.IsBoolType()) { |
| 334 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 334 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
| 335 __ j(EQUAL, is_instance_lbl); | 335 __ j(EQUAL, is_instance_lbl); |
| 336 __ jmp(is_not_instance_lbl); | 336 __ jmp(is_not_instance_lbl); |
| 337 return false; | 337 return false; |
| 338 } | 338 } |
| 339 if (type.IsFunctionType()) { | 339 if (type.IsFunctionType()) { |
| 340 // Check if instance is a closure. | 340 // Check if instance is a closure. |
| 341 __ LoadClassById(R13, kClassIdReg); | 341 __ LoadClassById(R13, kClassIdReg); |
| 342 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); | 342 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); |
| 343 __ CompareObject(R13, Object::Handle()); | 343 __ CompareObject(R13, Object::null_object()); |
| 344 __ j(NOT_EQUAL, is_instance_lbl); | 344 __ j(NOT_EQUAL, is_instance_lbl); |
| 345 } | 345 } |
| 346 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 346 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 347 // Note that instance is not Smi (checked above). | 347 // Note that instance is not Smi (checked above). |
| 348 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 348 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 349 GenerateNumberTypeCheck( | 349 GenerateNumberTypeCheck( |
| 350 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 350 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 351 return false; | 351 return false; |
| 352 } | 352 } |
| 353 if (type.IsStringType()) { | 353 if (type.IsStringType()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 Label* is_not_instance_lbl) { | 402 Label* is_not_instance_lbl) { |
| 403 __ Comment("UninstantiatedTypeTest"); | 403 __ Comment("UninstantiatedTypeTest"); |
| 404 ASSERT(!type.IsInstantiated()); | 404 ASSERT(!type.IsInstantiated()); |
| 405 // Skip check if destination is a dynamic type. | 405 // Skip check if destination is a dynamic type. |
| 406 if (type.IsTypeParameter()) { | 406 if (type.IsTypeParameter()) { |
| 407 const TypeParameter& type_param = TypeParameter::Cast(type); | 407 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 408 // Load instantiator (or null) and instantiator type arguments on stack. | 408 // Load instantiator (or null) and instantiator type arguments on stack. |
| 409 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 409 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 410 // RDX: instantiator type arguments. | 410 // RDX: instantiator type arguments. |
| 411 // Check if type argument is dynamic. | 411 // Check if type argument is dynamic. |
| 412 __ CompareObject(RDX, Object::Handle()); | 412 __ CompareObject(RDX, Object::null_object()); |
| 413 __ j(EQUAL, is_instance_lbl); | 413 __ j(EQUAL, is_instance_lbl); |
| 414 // Can handle only type arguments that are instances of TypeArguments. | 414 // Can handle only type arguments that are instances of TypeArguments. |
| 415 // (runtime checks canonicalize type arguments). | 415 // (runtime checks canonicalize type arguments). |
| 416 Label fall_through; | 416 Label fall_through; |
| 417 __ CompareClassId(RDX, kTypeArgumentsCid); | 417 __ CompareClassId(RDX, kTypeArgumentsCid); |
| 418 __ j(NOT_EQUAL, &fall_through); | 418 __ j(NOT_EQUAL, &fall_through); |
| 419 __ movq(RDI, | 419 __ movq(RDI, |
| 420 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 420 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); |
| 421 // RDI: Concrete type of type. | 421 // RDI: Concrete type of type. |
| 422 // Check if type argument is dynamic. | 422 // Check if type argument is dynamic. |
| 423 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); | 423 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); |
| 424 __ j(EQUAL, is_instance_lbl); | 424 __ j(EQUAL, is_instance_lbl); |
| 425 __ CompareObject(RDI, Object::Handle()); | 425 __ CompareObject(RDI, Object::null_object()); |
| 426 __ j(EQUAL, is_instance_lbl); | 426 __ j(EQUAL, is_instance_lbl); |
| 427 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 427 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
| 428 __ CompareObject(RDI, object_type); | 428 __ CompareObject(RDI, object_type); |
| 429 __ j(EQUAL, is_instance_lbl); | 429 __ j(EQUAL, is_instance_lbl); |
| 430 | 430 |
| 431 // For Smi check quickly against int and num interfaces. | 431 // For Smi check quickly against int and num interfaces. |
| 432 Label not_smi; | 432 Label not_smi; |
| 433 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 433 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 434 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 434 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 435 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType())); | 435 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType())); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 // If type is instantiated and non-parameterized, we can inline code | 568 // If type is instantiated and non-parameterized, we can inline code |
| 569 // checking whether the tested instance is a Smi. | 569 // checking whether the tested instance is a Smi. |
| 570 if (type.IsInstantiated()) { | 570 if (type.IsInstantiated()) { |
| 571 // A null object is only an instance of Object and dynamic, which has | 571 // A null object is only an instance of Object and dynamic, which has |
| 572 // already been checked above (if the type is instantiated). So we can | 572 // already been checked above (if the type is instantiated). So we can |
| 573 // return false here if the instance is null (and if the type is | 573 // return false here if the instance is null (and if the type is |
| 574 // instantiated). | 574 // instantiated). |
| 575 // We can only inline this null check if the type is instantiated at compile | 575 // We can only inline this null check if the type is instantiated at compile |
| 576 // time, since an uninstantiated type at compile time could be Object or | 576 // time, since an uninstantiated type at compile time could be Object or |
| 577 // dynamic at run time. | 577 // dynamic at run time. |
| 578 __ CompareObject(RAX, Object::Handle()); | 578 __ CompareObject(RAX, Object::null_object()); |
| 579 __ j(EQUAL, &is_not_instance); | 579 __ j(EQUAL, &is_not_instance); |
| 580 } | 580 } |
| 581 | 581 |
| 582 // Generate inline instanceof test. | 582 // Generate inline instanceof test. |
| 583 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 583 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 584 test_cache = GenerateInlineInstanceof(token_pos, type, | 584 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 585 &is_instance, &is_not_instance); | 585 &is_instance, &is_not_instance); |
| 586 | 586 |
| 587 // test_cache is null if there is no fall-through. | 587 // test_cache is null if there is no fall-through. |
| 588 Label done; | 588 Label done; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 ASSERT(token_pos >= 0); | 648 ASSERT(token_pos >= 0); |
| 649 ASSERT(!dst_type.IsNull()); | 649 ASSERT(!dst_type.IsNull()); |
| 650 ASSERT(dst_type.IsFinalized()); | 650 ASSERT(dst_type.IsFinalized()); |
| 651 // Assignable check is skipped in FlowGraphBuilder, not here. | 651 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 652 ASSERT(dst_type.IsMalformed() || dst_type.IsMalbounded() || | 652 ASSERT(dst_type.IsMalformed() || dst_type.IsMalbounded() || |
| 653 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 653 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 654 __ pushq(RCX); // Store instantiator. | 654 __ pushq(RCX); // Store instantiator. |
| 655 __ pushq(RDX); // Store instantiator type arguments. | 655 __ pushq(RDX); // Store instantiator type arguments. |
| 656 // A null object is always assignable and is returned as result. | 656 // A null object is always assignable and is returned as result. |
| 657 Label is_assignable, runtime_call; | 657 Label is_assignable, runtime_call; |
| 658 __ CompareObject(RAX, Object::Handle()); | 658 __ CompareObject(RAX, Object::null_object()); |
| 659 __ j(EQUAL, &is_assignable); | 659 __ j(EQUAL, &is_assignable); |
| 660 | 660 |
| 661 if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) { | 661 if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) { |
| 662 // If type checks are not eliminated during the graph building then | 662 // If type checks are not eliminated during the graph building then |
| 663 // a transition sentinel can be seen here. | 663 // a transition sentinel can be seen here. |
| 664 __ CompareObject(RAX, Object::transition_sentinel()); | 664 __ CompareObject(RAX, Object::transition_sentinel()); |
| 665 __ j(EQUAL, &is_assignable); | 665 __ j(EQUAL, &is_assignable); |
| 666 } | 666 } |
| 667 | 667 |
| 668 // Generate throw new TypeError() if the type is malformed or malbounded. | 668 // Generate throw new TypeError() if the type is malformed or malbounded. |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 // to be copied to the context that is not yet allocated. | 952 // to be copied to the context that is not yet allocated. |
| 953 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 953 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 954 const Address param_addr(RBP, computed_param_pos * kWordSize); | 954 const Address param_addr(RBP, computed_param_pos * kWordSize); |
| 955 __ movq(param_addr, RAX); | 955 __ movq(param_addr, RAX); |
| 956 } | 956 } |
| 957 delete[] opt_param; | 957 delete[] opt_param; |
| 958 delete[] opt_param_position; | 958 delete[] opt_param_position; |
| 959 if (check_correct_named_args) { | 959 if (check_correct_named_args) { |
| 960 // Check that RDI now points to the null terminator in the arguments | 960 // Check that RDI now points to the null terminator in the arguments |
| 961 // descriptor. | 961 // descriptor. |
| 962 __ LoadObject(TMP, Object::Handle(), PP); | 962 __ LoadObject(TMP, Object::null_object(), PP); |
| 963 __ cmpq(Address(RDI, 0), TMP); | 963 __ cmpq(Address(RDI, 0), TMP); |
| 964 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 964 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 965 } | 965 } |
| 966 } else { | 966 } else { |
| 967 ASSERT(num_opt_pos_params > 0); | 967 ASSERT(num_opt_pos_params > 0); |
| 968 __ movq(RCX, | 968 __ movq(RCX, |
| 969 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 969 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 970 __ SmiUntag(RCX); | 970 __ SmiUntag(RCX); |
| 971 for (int i = 0; i < num_opt_pos_params; i++) { | 971 for (int i = 0; i < num_opt_pos_params; i++) { |
| 972 Label next_parameter; | 972 Label next_parameter; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1017 __ Bind(&all_arguments_processed); | 1017 __ Bind(&all_arguments_processed); |
| 1018 // Nullify originally passed arguments only after they have been copied and | 1018 // Nullify originally passed arguments only after they have been copied and |
| 1019 // checked, otherwise noSuchMethod would not see their original values. | 1019 // checked, otherwise noSuchMethod would not see their original values. |
| 1020 // This step can be skipped in case we decide that formal parameters are | 1020 // This step can be skipped in case we decide that formal parameters are |
| 1021 // implicitly final, since garbage collecting the unmodified value is not | 1021 // implicitly final, since garbage collecting the unmodified value is not |
| 1022 // an issue anymore. | 1022 // an issue anymore. |
| 1023 | 1023 |
| 1024 // R10 : arguments descriptor array. | 1024 // R10 : arguments descriptor array. |
| 1025 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1025 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1026 __ SmiUntag(RCX); | 1026 __ SmiUntag(RCX); |
| 1027 __ LoadObject(R12, Object::Handle(), PP); | 1027 __ LoadObject(R12, Object::null_object(), PP); |
| 1028 Label null_args_loop, null_args_loop_condition; | 1028 Label null_args_loop, null_args_loop_condition; |
| 1029 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 1029 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 1030 const Address original_argument_addr( | 1030 const Address original_argument_addr( |
| 1031 RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize); | 1031 RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize); |
| 1032 __ Bind(&null_args_loop); | 1032 __ Bind(&null_args_loop); |
| 1033 __ movq(original_argument_addr, R12); | 1033 __ movq(original_argument_addr, R12); |
| 1034 __ Bind(&null_args_loop_condition); | 1034 __ Bind(&null_args_loop_condition); |
| 1035 __ decq(RCX); | 1035 __ decq(RCX); |
| 1036 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 1036 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 1037 } | 1037 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1048 | 1048 |
| 1049 | 1049 |
| 1050 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 1050 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 1051 // TOS: return address. | 1051 // TOS: return address. |
| 1052 // +1 : value | 1052 // +1 : value |
| 1053 // +2 : receiver. | 1053 // +2 : receiver. |
| 1054 // Sequence node has one store node and one return NULL node. | 1054 // Sequence node has one store node and one return NULL node. |
| 1055 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. | 1055 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. |
| 1056 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. | 1056 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. |
| 1057 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); | 1057 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); |
| 1058 __ LoadObject(RAX, Object::Handle(), PP); | 1058 __ LoadObject(RAX, Object::null_object(), PP); |
| 1059 __ ret(); | 1059 __ ret(); |
| 1060 } | 1060 } |
| 1061 | 1061 |
| 1062 | 1062 |
| 1063 void FlowGraphCompiler::EmitFrameEntry() { | 1063 void FlowGraphCompiler::EmitFrameEntry() { |
| 1064 const Function& function = parsed_function().function(); | 1064 const Function& function = parsed_function().function(); |
| 1065 Register new_pp = kNoRegister; | 1065 Register new_pp = kNoRegister; |
| 1066 Register new_pc = kNoRegister; | 1066 Register new_pc = kNoRegister; |
| 1067 if (CanOptimizeFunction() && | 1067 if (CanOptimizeFunction() && |
| 1068 function.is_optimizable() && | 1068 function.is_optimizable() && |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 } | 1210 } |
| 1211 } else if (!flow_graph().IsCompiledForOsr()) { | 1211 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1212 CopyParameters(); | 1212 CopyParameters(); |
| 1213 } | 1213 } |
| 1214 | 1214 |
| 1215 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1215 // In unoptimized code, initialize (non-argument) stack allocated slots to |
| 1216 // null. | 1216 // null. |
| 1217 if (!is_optimizing() && (num_locals > 0)) { | 1217 if (!is_optimizing() && (num_locals > 0)) { |
| 1218 __ Comment("Initialize spill slots"); | 1218 __ Comment("Initialize spill slots"); |
| 1219 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1219 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
| 1220 __ LoadObject(RAX, Object::Handle(), PP); | 1220 __ LoadObject(RAX, Object::null_object(), PP); |
| 1221 for (intptr_t i = 0; i < num_locals; ++i) { | 1221 for (intptr_t i = 0; i < num_locals; ++i) { |
| 1222 // Subtract index i (locals lie at lower addresses than RBP). | 1222 // Subtract index i (locals lie at lower addresses than RBP). |
| 1223 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); | 1223 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); |
| 1224 } | 1224 } |
| 1225 } | 1225 } |
| 1226 | 1226 |
| 1227 if (FLAG_print_scopes) { | 1227 if (FLAG_print_scopes) { |
| 1228 // Print the function scope (again) after generating the prologue in order | 1228 // Print the function scope (again) after generating the prologue in order |
| 1229 // to see annotations such as allocation indices of locals. | 1229 // to see annotations such as allocation indices of locals. |
| 1230 if (FLAG_print_ast) { | 1230 if (FLAG_print_ast) { |
| (...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1933 __ movups(reg, Address(RSP, 0)); | 1933 __ movups(reg, Address(RSP, 0)); |
| 1934 __ addq(RSP, Immediate(kFpuRegisterSize)); | 1934 __ addq(RSP, Immediate(kFpuRegisterSize)); |
| 1935 } | 1935 } |
| 1936 | 1936 |
| 1937 | 1937 |
| 1938 #undef __ | 1938 #undef __ |
| 1939 | 1939 |
| 1940 } // namespace dart | 1940 } // namespace dart |
| 1941 | 1941 |
| 1942 #endif // defined TARGET_ARCH_X64 | 1942 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |