| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 const intptr_t from_index = num_type_args - num_type_params; | 248 const intptr_t from_index = num_type_args - num_type_params; |
| 249 const TypeArguments& type_arguments = | 249 const TypeArguments& type_arguments = |
| 250 TypeArguments::ZoneHandle(type.arguments()); | 250 TypeArguments::ZoneHandle(type.arguments()); |
| 251 const bool is_raw_type = type_arguments.IsNull() || | 251 const bool is_raw_type = type_arguments.IsNull() || |
| 252 type_arguments.IsRaw(from_index, num_type_params); | 252 type_arguments.IsRaw(from_index, num_type_params); |
| 253 // Signature class is an instantiated parameterized type. | 253 // Signature class is an instantiated parameterized type. |
| 254 if (!type_class.IsSignatureClass()) { | 254 if (!type_class.IsSignatureClass()) { |
| 255 if (is_raw_type) { | 255 if (is_raw_type) { |
| 256 const Register kClassIdReg = R2; | 256 const Register kClassIdReg = R2; |
| 257 // dynamic type argument, check only classes. | 257 // dynamic type argument, check only classes. |
| 258 __ LoadClassId(kClassIdReg, kInstanceReg); | 258 __ LoadClassId(kClassIdReg, kInstanceReg, PP); |
| 259 __ CompareImmediate(kClassIdReg, type_class.id(), PP); | 259 __ CompareImmediate(kClassIdReg, type_class.id(), PP); |
| 260 __ b(is_instance_lbl, EQ); | 260 __ b(is_instance_lbl, EQ); |
| 261 // List is a very common case. | 261 // List is a very common case. |
| 262 if (IsListClass(type_class)) { | 262 if (IsListClass(type_class)) { |
| 263 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 263 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 264 } | 264 } |
| 265 return GenerateSubtype1TestCacheLookup( | 265 return GenerateSubtype1TestCacheLookup( |
| 266 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 266 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 267 } | 267 } |
| 268 // If one type argument only, check if type argument is Object or dynamic. | 268 // If one type argument only, check if type argument is Object or dynamic. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 329 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 330 type_class, | 330 type_class, |
| 331 TypeArguments::Handle(), | 331 TypeArguments::Handle(), |
| 332 NULL)) { | 332 NULL)) { |
| 333 __ b(is_instance_lbl, EQ); | 333 __ b(is_instance_lbl, EQ); |
| 334 } else { | 334 } else { |
| 335 __ b(is_not_instance_lbl, EQ); | 335 __ b(is_not_instance_lbl, EQ); |
| 336 } | 336 } |
| 337 // Compare if the classes are equal. | 337 // Compare if the classes are equal. |
| 338 const Register kClassIdReg = R2; | 338 const Register kClassIdReg = R2; |
| 339 __ LoadClassId(kClassIdReg, kInstanceReg); | 339 __ LoadClassId(kClassIdReg, kInstanceReg, PP); |
| 340 __ CompareImmediate(kClassIdReg, type_class.id(), PP); | 340 __ CompareImmediate(kClassIdReg, type_class.id(), PP); |
| 341 __ b(is_instance_lbl, EQ); | 341 __ b(is_instance_lbl, EQ); |
| 342 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 342 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 343 // interfaces. | 343 // interfaces. |
| 344 // Bool interface can be implemented only by core class Bool. | 344 // Bool interface can be implemented only by core class Bool. |
| 345 if (type.IsBoolType()) { | 345 if (type.IsBoolType()) { |
| 346 __ CompareImmediate(kClassIdReg, kBoolCid, PP); | 346 __ CompareImmediate(kClassIdReg, kBoolCid, PP); |
| 347 __ b(is_instance_lbl, EQ); | 347 __ b(is_instance_lbl, EQ); |
| 348 __ b(is_not_instance_lbl); | 348 __ b(is_not_instance_lbl); |
| 349 return false; | 349 return false; |
| 350 } | 350 } |
| 351 if (type.IsFunctionType()) { | 351 if (type.IsFunctionType()) { |
| 352 // Check if instance is a closure. | 352 // Check if instance is a closure. |
| 353 __ LoadClassById(R3, kClassIdReg); | 353 __ LoadClassById(R3, kClassIdReg, PP); |
| 354 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset()); | 354 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset(), PP); |
| 355 __ CompareObject(R3, Object::null_object(), PP); | 355 __ CompareObject(R3, Object::null_object(), PP); |
| 356 __ b(is_instance_lbl, NE); | 356 __ b(is_instance_lbl, NE); |
| 357 } | 357 } |
| 358 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 358 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 359 // Note that instance is not Smi (checked above). | 359 // Note that instance is not Smi (checked above). |
| 360 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 360 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 361 GenerateNumberTypeCheck( | 361 GenerateNumberTypeCheck( |
| 362 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 362 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 363 return false; | 363 return false; |
| 364 } | 364 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 378 // TODO(srdjan): Implement a quicker subtype check, as type test | 378 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 379 // arrays can grow too high, but they may be useful when optimizing | 379 // arrays can grow too high, but they may be useful when optimizing |
| 380 // code (type-feedback). | 380 // code (type-feedback). |
| 381 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 381 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| 382 intptr_t token_pos, | 382 intptr_t token_pos, |
| 383 const Class& type_class, | 383 const Class& type_class, |
| 384 Label* is_instance_lbl, | 384 Label* is_instance_lbl, |
| 385 Label* is_not_instance_lbl) { | 385 Label* is_not_instance_lbl) { |
| 386 __ Comment("Subtype1TestCacheLookup"); | 386 __ Comment("Subtype1TestCacheLookup"); |
| 387 const Register kInstanceReg = R0; | 387 const Register kInstanceReg = R0; |
| 388 __ LoadClass(R1, kInstanceReg); | 388 __ LoadClass(R1, kInstanceReg, PP); |
| 389 // R1: instance class. | 389 // R1: instance class. |
| 390 // Check immediate superclass equality. | 390 // Check immediate superclass equality. |
| 391 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset()); | 391 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset(), PP); |
| 392 __ LoadFieldFromOffset(R2, R2, Type::type_class_offset()); | 392 __ LoadFieldFromOffset(R2, R2, Type::type_class_offset(), PP); |
| 393 __ CompareObject(R2, type_class, PP); | 393 __ CompareObject(R2, type_class, PP); |
| 394 __ b(is_instance_lbl, EQ); | 394 __ b(is_instance_lbl, EQ); |
| 395 | 395 |
| 396 const Register kTypeArgumentsReg = kNoRegister; | 396 const Register kTypeArgumentsReg = kNoRegister; |
| 397 const Register kTempReg = kNoRegister; | 397 const Register kTempReg = kNoRegister; |
| 398 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 398 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
| 399 kInstanceReg, | 399 kInstanceReg, |
| 400 kTypeArgumentsReg, | 400 kTypeArgumentsReg, |
| 401 kTempReg, | 401 kTempReg, |
| 402 is_instance_lbl, | 402 is_instance_lbl, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 416 // Skip check if destination is a dynamic type. | 416 // Skip check if destination is a dynamic type. |
| 417 if (type.IsTypeParameter()) { | 417 if (type.IsTypeParameter()) { |
| 418 const TypeParameter& type_param = TypeParameter::Cast(type); | 418 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 419 // Load instantiator (or null) and instantiator type arguments on stack. | 419 // Load instantiator (or null) and instantiator type arguments on stack. |
| 420 __ ldr(R1, Address(SP)); // Get instantiator type arguments. | 420 __ ldr(R1, Address(SP)); // Get instantiator type arguments. |
| 421 // R1: instantiator type arguments. | 421 // R1: instantiator type arguments. |
| 422 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 422 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 423 __ CompareObject(R1, Object::null_object(), PP); | 423 __ CompareObject(R1, Object::null_object(), PP); |
| 424 __ b(is_instance_lbl, EQ); | 424 __ b(is_instance_lbl, EQ); |
| 425 __ LoadFieldFromOffset( | 425 __ LoadFieldFromOffset( |
| 426 R2, R1, TypeArguments::type_at_offset(type_param.index())); | 426 R2, R1, TypeArguments::type_at_offset(type_param.index()), PP); |
| 427 // R2: concrete type of type. | 427 // R2: concrete type of type. |
| 428 // Check if type argument is dynamic. | 428 // Check if type argument is dynamic. |
| 429 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()), PP); | 429 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()), PP); |
| 430 __ b(is_instance_lbl, EQ); | 430 __ b(is_instance_lbl, EQ); |
| 431 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()), PP); | 431 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()), PP); |
| 432 __ b(is_instance_lbl, EQ); | 432 __ b(is_instance_lbl, EQ); |
| 433 | 433 |
| 434 // For Smi check quickly against int and num interfaces. | 434 // For Smi check quickly against int and num interfaces. |
| 435 Label not_smi; | 435 Label not_smi; |
| 436 __ tsti(R0, kSmiTagMask); // Value is Smi? | 436 __ tsti(R0, kSmiTagMask); // Value is Smi? |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 num_fixed_params + num_opt_pos_params + num_opt_named_params; | 731 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| 732 ASSERT(function.NumParameters() == num_params); | 732 ASSERT(function.NumParameters() == num_params); |
| 733 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); | 733 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); |
| 734 | 734 |
| 735 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 735 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 736 // where num_pos_args is the number of positional arguments passed in. | 736 // where num_pos_args is the number of positional arguments passed in. |
| 737 const int min_num_pos_args = num_fixed_params; | 737 const int min_num_pos_args = num_fixed_params; |
| 738 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 738 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 739 | 739 |
| 740 __ LoadFieldFromOffset( | 740 __ LoadFieldFromOffset( |
| 741 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 741 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); |
| 742 // Check that min_num_pos_args <= num_pos_args. | 742 // Check that min_num_pos_args <= num_pos_args. |
| 743 Label wrong_num_arguments; | 743 Label wrong_num_arguments; |
| 744 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args), PP); | 744 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args), PP); |
| 745 __ b(&wrong_num_arguments, LT); | 745 __ b(&wrong_num_arguments, LT); |
| 746 // Check that num_pos_args <= max_num_pos_args. | 746 // Check that num_pos_args <= max_num_pos_args. |
| 747 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args), PP); | 747 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args), PP); |
| 748 __ b(&wrong_num_arguments, GT); | 748 __ b(&wrong_num_arguments, GT); |
| 749 | 749 |
| 750 // Copy positional arguments. | 750 // Copy positional arguments. |
| 751 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 751 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
| 752 // to fp[kFirstLocalSlotFromFp - i]. | 752 // to fp[kFirstLocalSlotFromFp - i]. |
| 753 | 753 |
| 754 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 754 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); |
| 755 // Since R7 and R8 are Smi, use LSL 2 instead of LSL 3. | 755 // Since R7 and R8 are Smi, use LSL 2 instead of LSL 3. |
| 756 // Let R7 point to the last passed positional argument, i.e. to | 756 // Let R7 point to the last passed positional argument, i.e. to |
| 757 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 757 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
| 758 __ sub(R7, R7, Operand(R8)); | 758 __ sub(R7, R7, Operand(R8)); |
| 759 __ add(R7, FP, Operand(R7, LSL, 2)); | 759 __ add(R7, FP, Operand(R7, LSL, 2)); |
| 760 __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize)); | 760 __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize)); |
| 761 | 761 |
| 762 // Let R6 point to the last copied positional argument, i.e. to | 762 // Let R6 point to the last copied positional argument, i.e. to |
| 763 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. | 763 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. |
| 764 __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize, PP); | 764 __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize, PP); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 798 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 799 ASSERT(result != 0); | 799 ASSERT(result != 0); |
| 800 if (result > 0) break; | 800 if (result > 0) break; |
| 801 opt_param[i + 1] = opt_param[i]; | 801 opt_param[i + 1] = opt_param[i]; |
| 802 opt_param_position[i + 1] = opt_param_position[i]; | 802 opt_param_position[i + 1] = opt_param_position[i]; |
| 803 } | 803 } |
| 804 opt_param[i + 1] = parameter; | 804 opt_param[i + 1] = parameter; |
| 805 opt_param_position[i + 1] = pos; | 805 opt_param_position[i + 1] = pos; |
| 806 } | 806 } |
| 807 // Generate code handling each optional parameter in alphabetical order. | 807 // Generate code handling each optional parameter in alphabetical order. |
| 808 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 808 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); |
| 809 __ LoadFieldFromOffset( | 809 __ LoadFieldFromOffset( |
| 810 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 810 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); |
| 811 __ SmiUntag(R8); | 811 __ SmiUntag(R8); |
| 812 // Let R7 point to the first passed argument, i.e. to | 812 // Let R7 point to the first passed argument, i.e. to |
| 813 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. | 813 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. |
| 814 __ add(R7, FP, Operand(R7, LSL, 2)); | 814 __ add(R7, FP, Operand(R7, LSL, 2)); |
| 815 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize, PP); | 815 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize, PP); |
| 816 // Let R6 point to the entry of the first named argument. | 816 // Let R6 point to the entry of the first named argument. |
| 817 __ add(R6, R4, Operand( | 817 __ add(R6, R4, Operand( |
| 818 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); | 818 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); |
| 819 for (int i = 0; i < num_opt_named_params; i++) { | 819 for (int i = 0; i < num_opt_named_params; i++) { |
| 820 Label load_default_value, assign_optional_parameter; | 820 Label load_default_value, assign_optional_parameter; |
| 821 const int param_pos = opt_param_position[i]; | 821 const int param_pos = opt_param_position[i]; |
| 822 // Check if this named parameter was passed in. | 822 // Check if this named parameter was passed in. |
| 823 // Load R5 with the name of the argument. | 823 // Load R5 with the name of the argument. |
| 824 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset()); | 824 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset(), PP); |
| 825 ASSERT(opt_param[i]->name().IsSymbol()); | 825 ASSERT(opt_param[i]->name().IsSymbol()); |
| 826 __ CompareObject(R5, opt_param[i]->name(), PP); | 826 __ CompareObject(R5, opt_param[i]->name(), PP); |
| 827 __ b(&load_default_value, NE); | 827 __ b(&load_default_value, NE); |
| 828 // Load R5 with passed-in argument at provided arg_pos, i.e. at | 828 // Load R5 with passed-in argument at provided arg_pos, i.e. at |
| 829 // fp[kParamEndSlotFromFp + num_args - arg_pos]. | 829 // fp[kParamEndSlotFromFp + num_args - arg_pos]. |
| 830 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset()); | 830 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset(), PP); |
| 831 // R5 is arg_pos as Smi. | 831 // R5 is arg_pos as Smi. |
| 832 // Point to next named entry. | 832 // Point to next named entry. |
| 833 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); | 833 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); |
| 834 // Negate and untag R5 so we can use in scaled address mode. | 834 // Negate and untag R5 so we can use in scaled address mode. |
| 835 __ subs(R5, ZR, Operand(R5, ASR, 1)); | 835 __ subs(R5, ZR, Operand(R5, ASR, 1)); |
| 836 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. | 836 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. |
| 837 __ ldr(R5, argument_addr); | 837 __ ldr(R5, argument_addr); |
| 838 __ b(&assign_optional_parameter); | 838 __ b(&assign_optional_parameter); |
| 839 __ Bind(&load_default_value); | 839 __ Bind(&load_default_value); |
| 840 // Load R5 with default argument. | 840 // Load R5 with default argument. |
| 841 const Object& value = Object::ZoneHandle( | 841 const Object& value = Object::ZoneHandle( |
| 842 parsed_function().default_parameter_values().At( | 842 parsed_function().default_parameter_values().At( |
| 843 param_pos - num_fixed_params)); | 843 param_pos - num_fixed_params)); |
| 844 __ LoadObject(R5, value, PP); | 844 __ LoadObject(R5, value, PP); |
| 845 __ Bind(&assign_optional_parameter); | 845 __ Bind(&assign_optional_parameter); |
| 846 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 846 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 847 // We do not use the final allocation index of the variable here, i.e. | 847 // We do not use the final allocation index of the variable here, i.e. |
| 848 // scope->VariableAt(i)->index(), because captured variables still need | 848 // scope->VariableAt(i)->index(), because captured variables still need |
| 849 // to be copied to the context that is not yet allocated. | 849 // to be copied to the context that is not yet allocated. |
| 850 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 850 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 851 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); | 851 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP); |
| 852 } | 852 } |
| 853 delete[] opt_param; | 853 delete[] opt_param; |
| 854 delete[] opt_param_position; | 854 delete[] opt_param_position; |
| 855 if (check_correct_named_args) { | 855 if (check_correct_named_args) { |
| 856 // Check that R6 now points to the null terminator in the arguments | 856 // Check that R6 now points to the null terminator in the arguments |
| 857 // descriptor. | 857 // descriptor. |
| 858 __ ldr(R5, Address(R6)); | 858 __ ldr(R5, Address(R6)); |
| 859 __ CompareObject(R5, Object::null_object(), PP); | 859 __ CompareObject(R5, Object::null_object(), PP); |
| 860 __ b(&all_arguments_processed, EQ); | 860 __ b(&all_arguments_processed, EQ); |
| 861 } | 861 } |
| 862 } else { | 862 } else { |
| 863 ASSERT(num_opt_pos_params > 0); | 863 ASSERT(num_opt_pos_params > 0); |
| 864 __ LoadFieldFromOffset( | 864 __ LoadFieldFromOffset( |
| 865 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 865 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); |
| 866 __ SmiUntag(R8); | 866 __ SmiUntag(R8); |
| 867 for (int i = 0; i < num_opt_pos_params; i++) { | 867 for (int i = 0; i < num_opt_pos_params; i++) { |
| 868 Label next_parameter; | 868 Label next_parameter; |
| 869 // Handle this optional positional parameter only if k or fewer positional | 869 // Handle this optional positional parameter only if k or fewer positional |
| 870 // arguments have been passed, where k is param_pos, the position of this | 870 // arguments have been passed, where k is param_pos, the position of this |
| 871 // optional parameter in the formal parameter list. | 871 // optional parameter in the formal parameter list. |
| 872 const int param_pos = num_fixed_params + i; | 872 const int param_pos = num_fixed_params + i; |
| 873 __ CompareImmediate(R8, param_pos, PP); | 873 __ CompareImmediate(R8, param_pos, PP); |
| 874 __ b(&next_parameter, GT); | 874 __ b(&next_parameter, GT); |
| 875 // Load R5 with default argument. | 875 // Load R5 with default argument. |
| 876 const Object& value = Object::ZoneHandle( | 876 const Object& value = Object::ZoneHandle( |
| 877 parsed_function().default_parameter_values().At(i)); | 877 parsed_function().default_parameter_values().At(i)); |
| 878 __ LoadObject(R5, value, PP); | 878 __ LoadObject(R5, value, PP); |
| 879 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 879 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 880 // We do not use the final allocation index of the variable here, i.e. | 880 // We do not use the final allocation index of the variable here, i.e. |
| 881 // scope->VariableAt(i)->index(), because captured variables still need | 881 // scope->VariableAt(i)->index(), because captured variables still need |
| 882 // to be copied to the context that is not yet allocated. | 882 // to be copied to the context that is not yet allocated. |
| 883 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 883 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 884 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); | 884 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP); |
| 885 __ Bind(&next_parameter); | 885 __ Bind(&next_parameter); |
| 886 } | 886 } |
| 887 if (check_correct_named_args) { | 887 if (check_correct_named_args) { |
| 888 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 888 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); |
| 889 __ SmiUntag(R7); | 889 __ SmiUntag(R7); |
| 890 // Check that R8 equals R7, i.e. no named arguments passed. | 890 // Check that R8 equals R7, i.e. no named arguments passed. |
| 891 __ CompareRegisters(R8, R7); | 891 __ CompareRegisters(R8, R7); |
| 892 __ b(&all_arguments_processed, EQ); | 892 __ b(&all_arguments_processed, EQ); |
| 893 } | 893 } |
| 894 } | 894 } |
| 895 | 895 |
| 896 __ Bind(&wrong_num_arguments); | 896 __ Bind(&wrong_num_arguments); |
| 897 if (function.IsClosureFunction()) { | 897 if (function.IsClosureFunction()) { |
| 898 // Invoke noSuchMethod function passing "call" as the original name. | 898 // Invoke noSuchMethod function passing "call" as the original name. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 910 } | 910 } |
| 911 | 911 |
| 912 __ Bind(&all_arguments_processed); | 912 __ Bind(&all_arguments_processed); |
| 913 // Nullify originally passed arguments only after they have been copied and | 913 // Nullify originally passed arguments only after they have been copied and |
| 914 // checked, otherwise noSuchMethod would not see their original values. | 914 // checked, otherwise noSuchMethod would not see their original values. |
| 915 // This step can be skipped in case we decide that formal parameters are | 915 // This step can be skipped in case we decide that formal parameters are |
| 916 // implicitly final, since garbage collecting the unmodified value is not | 916 // implicitly final, since garbage collecting the unmodified value is not |
| 917 // an issue anymore. | 917 // an issue anymore. |
| 918 | 918 |
| 919 // R4 : arguments descriptor array. | 919 // R4 : arguments descriptor array. |
| 920 __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset()); | 920 __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset(), PP); |
| 921 __ SmiUntag(R8); | 921 __ SmiUntag(R8); |
| 922 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); | 922 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); |
| 923 const Address original_argument_addr(R7, R8, UXTX, Address::Scaled); | 923 const Address original_argument_addr(R7, R8, UXTX, Address::Scaled); |
| 924 __ LoadObject(TMP, Object::null_object(), PP); | 924 __ LoadObject(TMP, Object::null_object(), PP); |
| 925 Label null_args_loop, null_args_loop_condition; | 925 Label null_args_loop, null_args_loop_condition; |
| 926 __ b(&null_args_loop_condition); | 926 __ b(&null_args_loop_condition); |
| 927 __ Bind(&null_args_loop); | 927 __ Bind(&null_args_loop); |
| 928 __ str(TMP, original_argument_addr); | 928 __ str(TMP, original_argument_addr); |
| 929 __ Bind(&null_args_loop_condition); | 929 __ Bind(&null_args_loop_condition); |
| 930 __ subs(R8, R8, Operand(1)); | 930 __ subs(R8, R8, Operand(1)); |
| 931 __ b(&null_args_loop, PL); | 931 __ b(&null_args_loop, PL); |
| 932 } | 932 } |
| 933 | 933 |
| 934 | 934 |
| 935 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 935 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 936 // LR: return address. | 936 // LR: return address. |
| 937 // SP: receiver. | 937 // SP: receiver. |
| 938 // Sequence node has one return node, its input is load field node. | 938 // Sequence node has one return node, its input is load field node. |
| 939 __ Comment("Inlined Getter"); | 939 __ Comment("Inlined Getter"); |
| 940 __ LoadFromOffset(R0, SP, 0 * kWordSize); | 940 __ LoadFromOffset(R0, SP, 0 * kWordSize, PP); |
| 941 __ LoadFromOffset(R0, R0, offset - kHeapObjectTag); | 941 __ LoadFromOffset(R0, R0, offset - kHeapObjectTag, PP); |
| 942 __ ret(); | 942 __ ret(); |
| 943 } | 943 } |
| 944 | 944 |
| 945 | 945 |
| 946 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 946 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 947 // LR: return address. | 947 // LR: return address. |
| 948 // SP+1: receiver. | 948 // SP+1: receiver. |
| 949 // SP+0: value. | 949 // SP+0: value. |
| 950 // Sequence node has one store node and one return NULL node. | 950 // Sequence node has one store node and one return NULL node. |
| 951 __ Comment("Inlined Setter"); | 951 __ Comment("Inlined Setter"); |
| 952 __ LoadFromOffset(R0, SP, 1 * kWordSize); // Receiver. | 952 __ LoadFromOffset(R0, SP, 1 * kWordSize, PP); // Receiver. |
| 953 __ LoadFromOffset(R1, SP, 0 * kWordSize); // Value. | 953 __ LoadFromOffset(R1, SP, 0 * kWordSize, PP); // Value. |
| 954 __ StoreIntoObject(R0, FieldAddress(R0, offset), R1); | 954 __ StoreIntoObjectOffset(R0, offset, R1, PP); |
| 955 __ LoadObject(R0, Object::null_object(), PP); | 955 __ LoadObject(R0, Object::null_object(), PP); |
| 956 __ ret(); | 956 __ ret(); |
| 957 } | 957 } |
| 958 | 958 |
| 959 | 959 |
| 960 void FlowGraphCompiler::EmitFrameEntry() { | 960 void FlowGraphCompiler::EmitFrameEntry() { |
| 961 const Function& function = parsed_function().function(); | 961 const Function& function = parsed_function().function(); |
| 962 Register new_pp = kNoPP; | 962 Register new_pp = kNoPP; |
| 963 if (CanOptimizeFunction() && | 963 if (CanOptimizeFunction() && |
| 964 function.IsOptimizable() && | 964 function.IsOptimizable() && |
| 965 (!is_optimizing() || may_reoptimize())) { | 965 (!is_optimizing() || may_reoptimize())) { |
| 966 const Register function_reg = R6; | 966 const Register function_reg = R6; |
| 967 new_pp = R13; | 967 new_pp = R13; |
| 968 | 968 |
| 969 // Set up pool pointer in new_pp. | 969 // Set up pool pointer in new_pp. |
| 970 __ LoadPoolPointer(new_pp); | 970 __ LoadPoolPointer(new_pp); |
| 971 | 971 |
| 972 // Load function object using the callee's pool pointer. | 972 // Load function object using the callee's pool pointer. |
| 973 __ LoadObject(function_reg, function, new_pp); | 973 __ LoadObject(function_reg, function, new_pp); |
| 974 | 974 |
| 975 // Patch point is after the eventually inlined function object. | 975 // Patch point is after the eventually inlined function object. |
| 976 AddCurrentDescriptor(PcDescriptors::kEntryPatch, | 976 AddCurrentDescriptor(PcDescriptors::kEntryPatch, |
| 977 Isolate::kNoDeoptId, | 977 Isolate::kNoDeoptId, |
| 978 0); // No token position. | 978 0); // No token position. |
| 979 intptr_t threshold = FLAG_optimization_counter_threshold; | 979 intptr_t threshold = FLAG_optimization_counter_threshold; |
| 980 __ LoadFieldFromOffset(R7, function_reg, Function::usage_counter_offset()); | 980 __ LoadFieldFromOffset( |
| 981 R7, function_reg, Function::usage_counter_offset(), new_pp); |
| 981 if (is_optimizing()) { | 982 if (is_optimizing()) { |
| 982 // Reoptimization of an optimized function is triggered by counting in | 983 // Reoptimization of an optimized function is triggered by counting in |
| 983 // IC stubs, but not at the entry of the function. | 984 // IC stubs, but not at the entry of the function. |
| 984 threshold = FLAG_reoptimization_counter_threshold; | 985 threshold = FLAG_reoptimization_counter_threshold; |
| 985 } else { | 986 } else { |
| 986 __ add(R7, R7, Operand(1)); | 987 __ add(R7, R7, Operand(1)); |
| 987 __ StoreFieldToOffset(R7, function_reg, Function::usage_counter_offset()); | 988 __ StoreFieldToOffset( |
| 989 R7, function_reg, Function::usage_counter_offset(), new_pp); |
| 988 } | 990 } |
| 989 __ CompareImmediate(R7, threshold, new_pp); | 991 __ CompareImmediate(R7, threshold, new_pp); |
| 990 ASSERT(function_reg == R6); | 992 ASSERT(function_reg == R6); |
| 991 Label dont_optimize; | 993 Label dont_optimize; |
| 992 __ b(&dont_optimize, LT); | 994 __ b(&dont_optimize, LT); |
| 993 __ Branch(&StubCode::OptimizeFunctionLabel(), new_pp); | 995 __ Branch(&StubCode::OptimizeFunctionLabel(), new_pp); |
| 994 __ Bind(&dont_optimize); | 996 __ Bind(&dont_optimize); |
| 995 } else if (!flow_graph().IsCompiledForOsr()) { | 997 } else if (!flow_graph().IsCompiledForOsr()) { |
| 996 // We have to load the PP here too because a load of an external label | 998 // We have to load the PP here too because a load of an external label |
| 997 // may be patched at the AddCurrentDescriptor below. | 999 // may be patched at the AddCurrentDescriptor below. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 ASSERT(!parsed_function().function().HasOptionalParameters()); | 1049 ASSERT(!parsed_function().function().HasOptionalParameters()); |
| 1048 const bool check_arguments = !flow_graph().IsCompiledForOsr(); | 1050 const bool check_arguments = !flow_graph().IsCompiledForOsr(); |
| 1049 #else | 1051 #else |
| 1050 const bool check_arguments = | 1052 const bool check_arguments = |
| 1051 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1053 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
| 1052 #endif | 1054 #endif |
| 1053 if (check_arguments) { | 1055 if (check_arguments) { |
| 1054 __ Comment("Check argument count"); | 1056 __ Comment("Check argument count"); |
| 1055 // Check that exactly num_fixed arguments are passed in. | 1057 // Check that exactly num_fixed arguments are passed in. |
| 1056 Label correct_num_arguments, wrong_num_arguments; | 1058 Label correct_num_arguments, wrong_num_arguments; |
| 1057 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset()); | 1059 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset(), PP); |
| 1058 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params), PP); | 1060 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params), PP); |
| 1059 __ b(&wrong_num_arguments, NE); | 1061 __ b(&wrong_num_arguments, NE); |
| 1060 __ LoadFieldFromOffset(R1, R4, | 1062 __ LoadFieldFromOffset(R1, R4, |
| 1061 ArgumentsDescriptor::positional_count_offset()); | 1063 ArgumentsDescriptor::positional_count_offset(), PP); |
| 1062 __ CompareRegisters(R0, R1); | 1064 __ CompareRegisters(R0, R1); |
| 1063 __ b(&correct_num_arguments, EQ); | 1065 __ b(&correct_num_arguments, EQ); |
| 1064 __ Bind(&wrong_num_arguments); | 1066 __ Bind(&wrong_num_arguments); |
| 1065 if (function.IsClosureFunction()) { | 1067 if (function.IsClosureFunction()) { |
| 1066 // Invoke noSuchMethod function passing the original function name. | 1068 // Invoke noSuchMethod function passing the original function name. |
| 1067 // For closure functions, use "call" as the original name. | 1069 // For closure functions, use "call" as the original name. |
| 1068 const String& name = | 1070 const String& name = |
| 1069 String::Handle(function.IsClosureFunction() | 1071 String::Handle(function.IsClosureFunction() |
| 1070 ? Symbols::Call().raw() | 1072 ? Symbols::Call().raw() |
| 1071 : function.name()); | 1073 : function.name()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1088 } | 1090 } |
| 1089 | 1091 |
| 1090 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1092 // In unoptimized code, initialize (non-argument) stack allocated slots to |
| 1091 // null. | 1093 // null. |
| 1092 if (!is_optimizing() && (num_locals > 0)) { | 1094 if (!is_optimizing() && (num_locals > 0)) { |
| 1093 __ Comment("Initialize spill slots"); | 1095 __ Comment("Initialize spill slots"); |
| 1094 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1096 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
| 1095 __ LoadObject(R0, Object::null_object(), PP); | 1097 __ LoadObject(R0, Object::null_object(), PP); |
| 1096 for (intptr_t i = 0; i < num_locals; ++i) { | 1098 for (intptr_t i = 0; i < num_locals; ++i) { |
| 1097 // Subtract index i (locals lie at lower addresses than FP). | 1099 // Subtract index i (locals lie at lower addresses than FP). |
| 1098 __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize); | 1100 __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize, PP); |
| 1099 } | 1101 } |
| 1100 } | 1102 } |
| 1101 | 1103 |
| 1102 VisitBlocks(); | 1104 VisitBlocks(); |
| 1103 | 1105 |
| 1104 __ hlt(0); | 1106 __ hlt(0); |
| 1105 GenerateDeferredCode(); | 1107 GenerateDeferredCode(); |
| 1106 // Emit function patching code. This will be swapped with the first 3 | 1108 // Emit function patching code. This will be swapped with the first 3 |
| 1107 // instructions at entry point. | 1109 // instructions at entry point. |
| 1108 AddCurrentDescriptor(PcDescriptors::kPatchCode, | 1110 AddCurrentDescriptor(PcDescriptors::kPatchCode, |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 void FlowGraphCompiler::EmitEdgeCounter() { | 1178 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1177 // We do not check for overflow when incrementing the edge counter. The | 1179 // We do not check for overflow when incrementing the edge counter. The |
| 1178 // function should normally be optimized long before the counter can | 1180 // function should normally be optimized long before the counter can |
| 1179 // overflow; and though we do not reset the counters when we optimize or | 1181 // overflow; and though we do not reset the counters when we optimize or |
| 1180 // deoptimize, there is a bound on the number of | 1182 // deoptimize, there is a bound on the number of |
| 1181 // optimization/deoptimization cycles we will attempt. | 1183 // optimization/deoptimization cycles we will attempt. |
| 1182 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1184 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); |
| 1183 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1185 counter.SetAt(0, Smi::Handle(Smi::New(0))); |
| 1184 __ Comment("Edge counter"); | 1186 __ Comment("Edge counter"); |
| 1185 __ LoadObject(R0, counter, PP); | 1187 __ LoadObject(R0, counter, PP); |
| 1186 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0)); | 1188 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0), PP); |
| 1187 __ add(TMP, TMP, Operand(Smi::RawValue(1))); | 1189 __ add(TMP, TMP, Operand(Smi::RawValue(1))); |
| 1188 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0)); | 1190 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0), PP); |
| 1189 } | 1191 } |
| 1190 | 1192 |
| 1191 | 1193 |
| 1192 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1194 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1193 ExternalLabel* target_label, | 1195 ExternalLabel* target_label, |
| 1194 const ICData& ic_data, | 1196 const ICData& ic_data, |
| 1195 intptr_t argument_count, | 1197 intptr_t argument_count, |
| 1196 intptr_t deopt_id, | 1198 intptr_t deopt_id, |
| 1197 intptr_t token_pos, | 1199 intptr_t token_pos, |
| 1198 LocationSummary* locs) { | 1200 LocationSummary* locs) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 intptr_t token_pos, | 1241 intptr_t token_pos, |
| 1240 LocationSummary* locs) { | 1242 LocationSummary* locs) { |
| 1241 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); | 1243 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); |
| 1242 const String& name = String::Handle(ic_data.target_name()); | 1244 const String& name = String::Handle(ic_data.target_name()); |
| 1243 const Array& arguments_descriptor = | 1245 const Array& arguments_descriptor = |
| 1244 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1246 Array::ZoneHandle(ic_data.arguments_descriptor()); |
| 1245 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1247 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1246 const MegamorphicCache& cache = | 1248 const MegamorphicCache& cache = |
| 1247 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1249 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); |
| 1248 Label not_smi, load_cache; | 1250 Label not_smi, load_cache; |
| 1249 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1251 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize, PP); |
| 1250 __ tsti(R0, kSmiTagMask); | 1252 __ tsti(R0, kSmiTagMask); |
| 1251 __ b(¬_smi, NE); | 1253 __ b(¬_smi, NE); |
| 1252 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), PP); | 1254 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), PP); |
| 1253 __ b(&load_cache); | 1255 __ b(&load_cache); |
| 1254 | 1256 |
| 1255 __ Bind(¬_smi); | 1257 __ Bind(¬_smi); |
| 1256 __ LoadClassId(R0, R0); | 1258 __ LoadClassId(R0, R0, PP); |
| 1257 __ SmiTag(R0); | 1259 __ SmiTag(R0); |
| 1258 | 1260 |
| 1259 // R0: class ID of the receiver (smi). | 1261 // R0: class ID of the receiver (smi). |
| 1260 __ Bind(&load_cache); | 1262 __ Bind(&load_cache); |
| 1261 __ LoadObject(R1, cache, PP); | 1263 __ LoadObject(R1, cache, PP); |
| 1262 __ LoadFieldFromOffset(R2, R1, MegamorphicCache::buckets_offset()); | 1264 __ LoadFieldFromOffset(R2, R1, MegamorphicCache::buckets_offset(), PP); |
| 1263 __ LoadFieldFromOffset(R1, R1, MegamorphicCache::mask_offset()); | 1265 __ LoadFieldFromOffset(R1, R1, MegamorphicCache::mask_offset(), PP); |
| 1264 // R2: cache buckets array. | 1266 // R2: cache buckets array. |
| 1265 // R1: mask. | 1267 // R1: mask. |
| 1266 __ mov(R3, R0); | 1268 __ mov(R3, R0); |
| 1267 | 1269 |
| 1268 Label loop, update, call_target_function; | 1270 Label loop, update, call_target_function; |
| 1269 __ b(&loop); | 1271 __ b(&loop); |
| 1270 | 1272 |
| 1271 __ Bind(&update); | 1273 __ Bind(&update); |
| 1272 __ add(R3, R3, Operand(Smi::RawValue(1))); | 1274 __ add(R3, R3, Operand(Smi::RawValue(1))); |
| 1273 __ Bind(&loop); | 1275 __ Bind(&loop); |
| 1274 __ and_(R3, R3, Operand(R1)); | 1276 __ and_(R3, R3, Operand(R1)); |
| 1275 const intptr_t base = Array::data_offset(); | 1277 const intptr_t base = Array::data_offset(); |
| 1276 // R3 is smi tagged, but table entries are 8 bytes, so LSL 2. | 1278 // R3 is smi tagged, but table entries are 8 bytes, so LSL 2. |
| 1277 __ add(TMP, R2, Operand(R3, LSL, 2)); | 1279 __ add(TMP, R2, Operand(R3, LSL, 2)); |
| 1278 __ LoadFieldFromOffset(R4, TMP, base); | 1280 __ LoadFieldFromOffset(R4, TMP, base, PP); |
| 1279 | 1281 |
| 1280 ASSERT(kIllegalCid == 0); | 1282 ASSERT(kIllegalCid == 0); |
| 1281 __ tst(R4, Operand(R4)); | 1283 __ tst(R4, Operand(R4)); |
| 1282 __ b(&call_target_function, EQ); | 1284 __ b(&call_target_function, EQ); |
| 1283 __ CompareRegisters(R4, R0); | 1285 __ CompareRegisters(R4, R0); |
| 1284 __ b(&update, NE); | 1286 __ b(&update, NE); |
| 1285 | 1287 |
| 1286 __ Bind(&call_target_function); | 1288 __ Bind(&call_target_function); |
| 1287 // Call the target found in the cache. For a class id match, this is a | 1289 // Call the target found in the cache. For a class id match, this is a |
| 1288 // proper target for the given name and arguments descriptor. If the | 1290 // proper target for the given name and arguments descriptor. If the |
| 1289 // illegal class id was found, the target is a cache miss handler that can | 1291 // illegal class id was found, the target is a cache miss handler that can |
| 1290 // be invoked as a normal Dart function. | 1292 // be invoked as a normal Dart function. |
| 1291 __ add(TMP, R2, Operand(R3, LSL, 2)); | 1293 __ add(TMP, R2, Operand(R3, LSL, 2)); |
| 1292 __ LoadFieldFromOffset(R0, TMP, base + kWordSize); | 1294 __ LoadFieldFromOffset(R0, TMP, base + kWordSize, PP); |
| 1293 __ LoadFieldFromOffset(R1, R0, Function::code_offset()); | 1295 __ LoadFieldFromOffset(R1, R0, Function::code_offset(), PP); |
| 1294 __ LoadFieldFromOffset(R1, R1, Code::instructions_offset()); | 1296 __ LoadFieldFromOffset(R1, R1, Code::instructions_offset(), PP); |
| 1295 __ LoadObject(R5, ic_data, PP); | 1297 __ LoadObject(R5, ic_data, PP); |
| 1296 __ LoadObject(R4, arguments_descriptor, PP); | 1298 __ LoadObject(R4, arguments_descriptor, PP); |
| 1297 __ AddImmediate(R1, R1, Instructions::HeaderSize() - kHeapObjectTag, PP); | 1299 __ AddImmediate(R1, R1, Instructions::HeaderSize() - kHeapObjectTag, PP); |
| 1298 __ blr(R1); | 1300 __ blr(R1); |
| 1299 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); | 1301 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| 1300 RecordSafepoint(locs); | 1302 RecordSafepoint(locs); |
| 1301 AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos); | 1303 AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos); |
| 1302 __ Drop(argument_count); | 1304 __ Drop(argument_count); |
| 1303 } | 1305 } |
| 1304 | 1306 |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 MoveOperands* move = moves_[index]; | 1570 MoveOperands* move = moves_[index]; |
| 1569 const Location source = move->src(); | 1571 const Location source = move->src(); |
| 1570 const Location destination = move->dest(); | 1572 const Location destination = move->dest(); |
| 1571 | 1573 |
| 1572 if (source.IsRegister()) { | 1574 if (source.IsRegister()) { |
| 1573 if (destination.IsRegister()) { | 1575 if (destination.IsRegister()) { |
| 1574 __ mov(destination.reg(), source.reg()); | 1576 __ mov(destination.reg(), source.reg()); |
| 1575 } else { | 1577 } else { |
| 1576 ASSERT(destination.IsStackSlot()); | 1578 ASSERT(destination.IsStackSlot()); |
| 1577 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1579 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1578 __ StoreToOffset(source.reg(), FP, dest_offset); | 1580 __ StoreToOffset(source.reg(), FP, dest_offset, PP); |
| 1579 } | 1581 } |
| 1580 } else if (source.IsStackSlot()) { | 1582 } else if (source.IsStackSlot()) { |
| 1581 if (destination.IsRegister()) { | 1583 if (destination.IsRegister()) { |
| 1582 const intptr_t source_offset = source.ToStackSlotOffset(); | 1584 const intptr_t source_offset = source.ToStackSlotOffset(); |
| 1583 __ LoadFromOffset(destination.reg(), FP, source_offset); | 1585 __ LoadFromOffset(destination.reg(), FP, source_offset, PP); |
| 1584 } else { | 1586 } else { |
| 1585 ASSERT(destination.IsStackSlot()); | 1587 ASSERT(destination.IsStackSlot()); |
| 1586 const intptr_t source_offset = source.ToStackSlotOffset(); | 1588 const intptr_t source_offset = source.ToStackSlotOffset(); |
| 1587 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1589 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1588 __ LoadFromOffset(TMP, FP, source_offset); | 1590 __ LoadFromOffset(TMP, FP, source_offset, PP); |
| 1589 __ StoreToOffset(TMP, FP, dest_offset); | 1591 __ StoreToOffset(TMP, FP, dest_offset, PP); |
| 1590 } | 1592 } |
| 1591 } else if (source.IsFpuRegister()) { | 1593 } else if (source.IsFpuRegister()) { |
| 1592 if (destination.IsFpuRegister()) { | 1594 if (destination.IsFpuRegister()) { |
| 1593 __ fmovdd(destination.fpu_reg(), source.fpu_reg()); | 1595 __ fmovdd(destination.fpu_reg(), source.fpu_reg()); |
| 1594 } else { | 1596 } else { |
| 1595 if (destination.IsDoubleStackSlot()) { | 1597 if (destination.IsDoubleStackSlot()) { |
| 1596 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1598 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1597 VRegister src = source.fpu_reg(); | 1599 VRegister src = source.fpu_reg(); |
| 1598 __ StoreDToOffset(src, FP, dest_offset); | 1600 __ StoreDToOffset(src, FP, dest_offset, PP); |
| 1599 } else { | 1601 } else { |
| 1600 ASSERT(destination.IsQuadStackSlot()); | 1602 ASSERT(destination.IsQuadStackSlot()); |
| 1601 UNIMPLEMENTED(); | 1603 UNIMPLEMENTED(); |
| 1602 } | 1604 } |
| 1603 } | 1605 } |
| 1604 } else if (source.IsDoubleStackSlot()) { | 1606 } else if (source.IsDoubleStackSlot()) { |
| 1605 if (destination.IsFpuRegister()) { | 1607 if (destination.IsFpuRegister()) { |
| 1606 const intptr_t dest_offset = source.ToStackSlotOffset(); | 1608 const intptr_t dest_offset = source.ToStackSlotOffset(); |
| 1607 const VRegister dst = destination.fpu_reg(); | 1609 const VRegister dst = destination.fpu_reg(); |
| 1608 __ LoadDFromOffset(dst, FP, dest_offset); | 1610 __ LoadDFromOffset(dst, FP, dest_offset, PP); |
| 1609 } else { | 1611 } else { |
| 1610 ASSERT(destination.IsDoubleStackSlot()); | 1612 ASSERT(destination.IsDoubleStackSlot()); |
| 1611 const intptr_t source_offset = source.ToStackSlotOffset(); | 1613 const intptr_t source_offset = source.ToStackSlotOffset(); |
| 1612 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1614 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1613 __ LoadDFromOffset(VTMP, FP, source_offset); | 1615 __ LoadDFromOffset(VTMP, FP, source_offset, PP); |
| 1614 __ StoreDToOffset(VTMP, FP, dest_offset); | 1616 __ StoreDToOffset(VTMP, FP, dest_offset, PP); |
| 1615 } | 1617 } |
| 1616 } else if (source.IsQuadStackSlot()) { | 1618 } else if (source.IsQuadStackSlot()) { |
| 1617 UNIMPLEMENTED(); | 1619 UNIMPLEMENTED(); |
| 1618 } else { | 1620 } else { |
| 1619 ASSERT(source.IsConstant()); | 1621 ASSERT(source.IsConstant()); |
| 1620 const Object& constant = source.constant(); | 1622 const Object& constant = source.constant(); |
| 1621 if (destination.IsRegister()) { | 1623 if (destination.IsRegister()) { |
| 1622 __ LoadObject(destination.reg(), constant, PP); | 1624 __ LoadObject(destination.reg(), constant, PP); |
| 1623 } else if (destination.IsFpuRegister()) { | 1625 } else if (destination.IsFpuRegister()) { |
| 1624 const VRegister dst = destination.fpu_reg(); | 1626 const VRegister dst = destination.fpu_reg(); |
| 1625 __ LoadObject(TMP, constant, PP); | 1627 __ LoadObject(TMP, constant, PP); |
| 1626 __ LoadDFieldFromOffset(dst, TMP, Double::value_offset()); | 1628 __ LoadDFieldFromOffset(dst, TMP, Double::value_offset(), PP); |
| 1627 } else if (destination.IsDoubleStackSlot()) { | 1629 } else if (destination.IsDoubleStackSlot()) { |
| 1628 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1630 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1629 __ LoadObject(TMP, constant, PP); | 1631 __ LoadObject(TMP, constant, PP); |
| 1630 __ LoadDFieldFromOffset(VTMP, TMP, Double::value_offset()); | 1632 __ LoadDFieldFromOffset(VTMP, TMP, Double::value_offset(), PP); |
| 1631 __ StoreDToOffset(VTMP, FP, dest_offset); | 1633 __ StoreDToOffset(VTMP, FP, dest_offset, PP); |
| 1632 } else { | 1634 } else { |
| 1633 ASSERT(destination.IsStackSlot()); | 1635 ASSERT(destination.IsStackSlot()); |
| 1634 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1636 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1635 __ LoadObject(TMP, constant, PP); | 1637 __ LoadObject(TMP, constant, PP); |
| 1636 __ StoreToOffset(TMP, FP, dest_offset); | 1638 __ StoreToOffset(TMP, FP, dest_offset, PP); |
| 1637 } | 1639 } |
| 1638 } | 1640 } |
| 1639 | 1641 |
| 1640 move->Eliminate(); | 1642 move->Eliminate(); |
| 1641 } | 1643 } |
| 1642 | 1644 |
| 1643 | 1645 |
| 1644 void ParallelMoveResolver::EmitSwap(int index) { | 1646 void ParallelMoveResolver::EmitSwap(int index) { |
| 1645 MoveOperands* move = moves_[index]; | 1647 MoveOperands* move = moves_[index]; |
| 1646 const Location source = move->src(); | 1648 const Location source = move->src(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1671 source.IsQuadStackSlot()); | 1673 source.IsQuadStackSlot()); |
| 1672 bool double_width = destination.IsDoubleStackSlot() || | 1674 bool double_width = destination.IsDoubleStackSlot() || |
| 1673 source.IsDoubleStackSlot(); | 1675 source.IsDoubleStackSlot(); |
| 1674 VRegister reg = source.IsFpuRegister() ? source.fpu_reg() | 1676 VRegister reg = source.IsFpuRegister() ? source.fpu_reg() |
| 1675 : destination.fpu_reg(); | 1677 : destination.fpu_reg(); |
| 1676 const intptr_t slot_offset = source.IsFpuRegister() | 1678 const intptr_t slot_offset = source.IsFpuRegister() |
| 1677 ? destination.ToStackSlotOffset() | 1679 ? destination.ToStackSlotOffset() |
| 1678 : source.ToStackSlotOffset(); | 1680 : source.ToStackSlotOffset(); |
| 1679 | 1681 |
| 1680 if (double_width) { | 1682 if (double_width) { |
| 1681 __ LoadDFromOffset(VTMP, FP, slot_offset); | 1683 __ LoadDFromOffset(VTMP, FP, slot_offset, PP); |
| 1682 __ StoreDToOffset(reg, FP, slot_offset); | 1684 __ StoreDToOffset(reg, FP, slot_offset, PP); |
| 1683 __ fmovdd(reg, VTMP); | 1685 __ fmovdd(reg, VTMP); |
| 1684 } else { | 1686 } else { |
| 1685 UNIMPLEMENTED(); | 1687 UNIMPLEMENTED(); |
| 1686 } | 1688 } |
| 1687 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { | 1689 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { |
| 1688 const intptr_t source_offset = source.ToStackSlotOffset(); | 1690 const intptr_t source_offset = source.ToStackSlotOffset(); |
| 1689 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1691 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
| 1690 | 1692 |
| 1691 ScratchFpuRegisterScope ensure_scratch(this, VTMP); | 1693 ScratchFpuRegisterScope ensure_scratch(this, VTMP); |
| 1692 VRegister scratch = ensure_scratch.reg(); | 1694 VRegister scratch = ensure_scratch.reg(); |
| 1693 __ LoadDFromOffset(VTMP, FP, source_offset); | 1695 __ LoadDFromOffset(VTMP, FP, source_offset, PP); |
| 1694 __ LoadDFromOffset(scratch, FP, dest_offset); | 1696 __ LoadDFromOffset(scratch, FP, dest_offset, PP); |
| 1695 __ StoreDToOffset(VTMP, FP, dest_offset); | 1697 __ StoreDToOffset(VTMP, FP, dest_offset, PP); |
| 1696 __ StoreDToOffset(scratch, FP, source_offset); | 1698 __ StoreDToOffset(scratch, FP, source_offset, PP); |
| 1697 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { | 1699 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { |
| 1698 UNIMPLEMENTED(); | 1700 UNIMPLEMENTED(); |
| 1699 } else { | 1701 } else { |
| 1700 UNREACHABLE(); | 1702 UNREACHABLE(); |
| 1701 } | 1703 } |
| 1702 | 1704 |
| 1703 // The swap of source and destination has executed a move from source to | 1705 // The swap of source and destination has executed a move from source to |
| 1704 // destination. | 1706 // destination. |
| 1705 move->Eliminate(); | 1707 move->Eliminate(); |
| 1706 | 1708 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1772 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1774 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1773 UNIMPLEMENTED(); | 1775 UNIMPLEMENTED(); |
| 1774 } | 1776 } |
| 1775 | 1777 |
| 1776 | 1778 |
| 1777 #undef __ | 1779 #undef __ |
| 1778 | 1780 |
| 1779 } // namespace dart | 1781 } // namespace dart |
| 1780 | 1782 |
| 1781 #endif // defined TARGET_ARCH_ARM64 | 1783 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |