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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
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 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 | 203 |
204 | 204 |
205 #define __ assembler()-> | 205 #define __ assembler()-> |
206 | 206 |
207 | 207 |
208 // Fall through if bool_register contains null. | 208 // Fall through if bool_register contains null. |
209 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 209 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
210 Label* is_true, | 210 Label* is_true, |
211 Label* is_false) { | 211 Label* is_false) { |
212 Label fall_through; | 212 Label fall_through; |
213 __ CompareImmediate(bool_register, | 213 __ CompareObject(bool_register, Object::null_object()); |
214 reinterpret_cast<intptr_t>(Object::null())); | |
215 __ b(&fall_through, EQ); | 214 __ b(&fall_through, EQ); |
216 __ CompareObject(bool_register, Bool::True()); | 215 __ CompareObject(bool_register, Bool::True()); |
217 __ b(is_true, EQ); | 216 __ b(is_true, EQ); |
218 __ b(is_false); | 217 __ b(is_false); |
219 __ Bind(&fall_through); | 218 __ Bind(&fall_through); |
220 } | 219 } |
221 | 220 |
222 | 221 |
223 // R0: instance (must be preserved). | 222 // R0: instance (must be preserved). |
224 // R1: instantiator type arguments (if used). | 223 // R1: instantiator type arguments (if used). |
225 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 224 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
226 TypeTestStubKind test_kind, | 225 TypeTestStubKind test_kind, |
227 Register instance_reg, | 226 Register instance_reg, |
228 Register type_arguments_reg, | 227 Register type_arguments_reg, |
229 Register temp_reg, | 228 Register temp_reg, |
230 Label* is_instance_lbl, | 229 Label* is_instance_lbl, |
231 Label* is_not_instance_lbl) { | 230 Label* is_not_instance_lbl) { |
232 ASSERT(instance_reg == R0); | 231 ASSERT(instance_reg == R0); |
233 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 232 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
234 const SubtypeTestCache& type_test_cache = | 233 const SubtypeTestCache& type_test_cache = |
235 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 234 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
236 __ LoadUniqueObject(R2, type_test_cache); | 235 __ LoadUniqueObject(R2, type_test_cache); |
237 if (test_kind == kTestTypeOneArg) { | 236 if (test_kind == kTestTypeOneArg) { |
238 ASSERT(type_arguments_reg == kNoRegister); | 237 ASSERT(type_arguments_reg == kNoRegister); |
239 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 238 __ LoadObject(R1, Object::null_object()); |
240 __ BranchLink(*StubCode::Subtype1TestCache_entry()); | 239 __ BranchLink(*StubCode::Subtype1TestCache_entry()); |
241 } else if (test_kind == kTestTypeTwoArgs) { | 240 } else if (test_kind == kTestTypeTwoArgs) { |
242 ASSERT(type_arguments_reg == kNoRegister); | 241 ASSERT(type_arguments_reg == kNoRegister); |
243 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 242 __ LoadObject(R1, Object::null_object()); |
244 __ BranchLink(*StubCode::Subtype2TestCache_entry()); | 243 __ BranchLink(*StubCode::Subtype2TestCache_entry()); |
245 } else if (test_kind == kTestTypeThreeArgs) { | 244 } else if (test_kind == kTestTypeThreeArgs) { |
246 ASSERT(type_arguments_reg == R1); | 245 ASSERT(type_arguments_reg == R1); |
247 __ BranchLink(*StubCode::Subtype3TestCache_entry()); | 246 __ BranchLink(*StubCode::Subtype3TestCache_entry()); |
248 } else { | 247 } else { |
249 UNREACHABLE(); | 248 UNREACHABLE(); |
250 } | 249 } |
251 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 250 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
252 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 251 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); |
253 return type_test_cache.raw(); | 252 return type_test_cache.raw(); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 if (type.IsBoolType()) { | 382 if (type.IsBoolType()) { |
384 __ CompareImmediate(kClassIdReg, kBoolCid); | 383 __ CompareImmediate(kClassIdReg, kBoolCid); |
385 __ b(is_instance_lbl, EQ); | 384 __ b(is_instance_lbl, EQ); |
386 __ b(is_not_instance_lbl); | 385 __ b(is_not_instance_lbl); |
387 return false; | 386 return false; |
388 } | 387 } |
389 if (type.IsFunctionType()) { | 388 if (type.IsFunctionType()) { |
390 // Check if instance is a closure. | 389 // Check if instance is a closure. |
391 __ LoadClassById(R3, kClassIdReg); | 390 __ LoadClassById(R3, kClassIdReg); |
392 __ ldr(R3, FieldAddress(R3, Class::signature_function_offset())); | 391 __ ldr(R3, FieldAddress(R3, Class::signature_function_offset())); |
393 __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null())); | 392 __ CompareObject(R3, Object::null_object()); |
394 __ b(is_instance_lbl, NE); | 393 __ b(is_instance_lbl, NE); |
395 } | 394 } |
396 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 395 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
397 // Note that instance is not Smi (checked above). | 396 // Note that instance is not Smi (checked above). |
398 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { | 397 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
399 GenerateNumberTypeCheck( | 398 GenerateNumberTypeCheck( |
400 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 399 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
401 return false; | 400 return false; |
402 } | 401 } |
403 if (type.IsStringType()) { | 402 if (type.IsStringType()) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 Label* is_not_instance_lbl) { | 450 Label* is_not_instance_lbl) { |
452 __ Comment("UninstantiatedTypeTest"); | 451 __ Comment("UninstantiatedTypeTest"); |
453 ASSERT(!type.IsInstantiated()); | 452 ASSERT(!type.IsInstantiated()); |
454 // Skip check if destination is a dynamic type. | 453 // Skip check if destination is a dynamic type. |
455 if (type.IsTypeParameter()) { | 454 if (type.IsTypeParameter()) { |
456 const TypeParameter& type_param = TypeParameter::Cast(type); | 455 const TypeParameter& type_param = TypeParameter::Cast(type); |
457 // Load instantiator (or null) and instantiator type arguments on stack. | 456 // Load instantiator (or null) and instantiator type arguments on stack. |
458 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 457 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. |
459 // R1: instantiator type arguments. | 458 // R1: instantiator type arguments. |
460 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 459 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
461 __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 460 __ CompareObject(R1, Object::null_object()); |
462 __ b(is_instance_lbl, EQ); | 461 __ b(is_instance_lbl, EQ); |
463 __ ldr(R2, | 462 __ ldr(R2, |
464 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | 463 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); |
465 // R2: concrete type of type. | 464 // R2: concrete type of type. |
466 // Check if type argument is dynamic. | 465 // Check if type argument is dynamic. |
467 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType())); | 466 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType())); |
468 __ b(is_instance_lbl, EQ); | 467 __ b(is_instance_lbl, EQ); |
469 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 468 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); |
470 __ b(is_instance_lbl, EQ); | 469 __ b(is_instance_lbl, EQ); |
471 | 470 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 // If type is instantiated and non-parameterized, we can inline code | 595 // If type is instantiated and non-parameterized, we can inline code |
597 // checking whether the tested instance is a Smi. | 596 // checking whether the tested instance is a Smi. |
598 if (type.IsInstantiated()) { | 597 if (type.IsInstantiated()) { |
599 // A null object is only an instance of Object and dynamic, which has | 598 // A null object is only an instance of Object and dynamic, which has |
600 // already been checked above (if the type is instantiated). So we can | 599 // already been checked above (if the type is instantiated). So we can |
601 // return false here if the instance is null (and if the type is | 600 // return false here if the instance is null (and if the type is |
602 // instantiated). | 601 // instantiated). |
603 // We can only inline this null check if the type is instantiated at compile | 602 // We can only inline this null check if the type is instantiated at compile |
604 // time, since an uninstantiated type at compile time could be Object or | 603 // time, since an uninstantiated type at compile time could be Object or |
605 // dynamic at run time. | 604 // dynamic at run time. |
606 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); | 605 __ CompareObject(R0, Object::null_object()); |
607 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 606 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
608 } | 607 } |
609 | 608 |
610 // Generate inline instanceof test. | 609 // Generate inline instanceof test. |
611 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 610 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
612 test_cache = GenerateInlineInstanceof(token_pos, type, | 611 test_cache = GenerateInlineInstanceof(token_pos, type, |
613 &is_instance, &is_not_instance); | 612 &is_instance, &is_not_instance); |
614 | 613 |
615 // test_cache is null if there is no fall-through. | 614 // test_cache is null if there is no fall-through. |
616 Label done; | 615 Label done; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 ASSERT(token_pos >= 0); | 671 ASSERT(token_pos >= 0); |
673 ASSERT(!dst_type.IsNull()); | 672 ASSERT(!dst_type.IsNull()); |
674 ASSERT(dst_type.IsFinalized()); | 673 ASSERT(dst_type.IsFinalized()); |
675 // Assignable check is skipped in FlowGraphBuilder, not here. | 674 // Assignable check is skipped in FlowGraphBuilder, not here. |
676 ASSERT(dst_type.IsMalformedOrMalbounded() || | 675 ASSERT(dst_type.IsMalformedOrMalbounded() || |
677 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 676 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
678 // Preserve instantiator (R2) and its type arguments (R1). | 677 // Preserve instantiator (R2) and its type arguments (R1). |
679 __ PushList((1 << R1) | (1 << R2)); | 678 __ PushList((1 << R1) | (1 << R2)); |
680 // A null object is always assignable and is returned as result. | 679 // A null object is always assignable and is returned as result. |
681 Label is_assignable, runtime_call; | 680 Label is_assignable, runtime_call; |
682 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); | 681 __ CompareObject(R0, Object::null_object()); |
683 __ b(&is_assignable, EQ); | 682 __ b(&is_assignable, EQ); |
684 | 683 |
685 // Generate throw new TypeError() if the type is malformed or malbounded. | 684 // Generate throw new TypeError() if the type is malformed or malbounded. |
686 if (dst_type.IsMalformedOrMalbounded()) { | 685 if (dst_type.IsMalformedOrMalbounded()) { |
687 __ PushObject(Object::null_object()); // Make room for the result. | 686 __ PushObject(Object::null_object()); // Make room for the result. |
688 __ Push(R0); // Push the source object. | 687 __ Push(R0); // Push the source object. |
689 __ PushObject(dst_name); // Push the name of the destination. | 688 __ PushObject(dst_name); // Push the name of the destination. |
690 __ PushObject(dst_type); // Push the type of the destination. | 689 __ PushObject(dst_type); // Push the type of the destination. |
691 GenerateRuntimeCall(token_pos, | 690 GenerateRuntimeCall(token_pos, |
692 deopt_id, | 691 deopt_id, |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 869 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
871 const Address param_addr(FP, computed_param_pos * kWordSize); | 870 const Address param_addr(FP, computed_param_pos * kWordSize); |
872 __ str(R5, param_addr); | 871 __ str(R5, param_addr); |
873 } | 872 } |
874 delete[] opt_param; | 873 delete[] opt_param; |
875 delete[] opt_param_position; | 874 delete[] opt_param_position; |
876 if (check_correct_named_args) { | 875 if (check_correct_named_args) { |
877 // Check that R6 now points to the null terminator in the arguments | 876 // Check that R6 now points to the null terminator in the arguments |
878 // descriptor. | 877 // descriptor. |
879 __ ldr(R5, Address(R6, 0)); | 878 __ ldr(R5, Address(R6, 0)); |
880 __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null())); | 879 __ CompareObject(R5, Object::null_object()); |
881 __ b(&all_arguments_processed, EQ); | 880 __ b(&all_arguments_processed, EQ); |
882 } | 881 } |
883 } else { | 882 } else { |
884 ASSERT(num_opt_pos_params > 0); | 883 ASSERT(num_opt_pos_params > 0); |
885 __ ldr(R9, | 884 __ ldr(R9, |
886 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 885 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
887 __ SmiUntag(R9); | 886 __ SmiUntag(R9); |
888 for (int i = 0; i < num_opt_pos_params; i++) { | 887 for (int i = 0; i < num_opt_pos_params; i++) { |
889 Label next_parameter; | 888 Label next_parameter; |
890 // Handle this optional positional parameter only if k or fewer positional | 889 // Handle this optional positional parameter only if k or fewer positional |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
932 // checked, otherwise noSuchMethod would not see their original values. | 931 // checked, otherwise noSuchMethod would not see their original values. |
933 // This step can be skipped in case we decide that formal parameters are | 932 // This step can be skipped in case we decide that formal parameters are |
934 // implicitly final, since garbage collecting the unmodified value is not | 933 // implicitly final, since garbage collecting the unmodified value is not |
935 // an issue anymore. | 934 // an issue anymore. |
936 | 935 |
937 // R4 : arguments descriptor array. | 936 // R4 : arguments descriptor array. |
938 __ ldr(R9, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 937 __ ldr(R9, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
939 __ SmiUntag(R9); | 938 __ SmiUntag(R9); |
940 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); | 939 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); |
941 const Address original_argument_addr(R7, R9, LSL, 2); | 940 const Address original_argument_addr(R7, R9, LSL, 2); |
942 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | 941 __ LoadObject(IP, Object::null_object()); |
943 Label null_args_loop, null_args_loop_condition; | 942 Label null_args_loop, null_args_loop_condition; |
944 __ b(&null_args_loop_condition); | 943 __ b(&null_args_loop_condition); |
945 __ Bind(&null_args_loop); | 944 __ Bind(&null_args_loop); |
946 __ str(IP, original_argument_addr); | 945 __ str(IP, original_argument_addr); |
947 __ Bind(&null_args_loop_condition); | 946 __ Bind(&null_args_loop_condition); |
948 __ subs(R9, R9, Operand(1)); | 947 __ subs(R9, R9, Operand(1)); |
949 __ b(&null_args_loop, PL); | 948 __ b(&null_args_loop, PL); |
950 } | 949 } |
951 | 950 |
952 | 951 |
(...skipping 10 matching lines...) Expand all Loading... |
963 | 962 |
964 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 963 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
965 // LR: return address. | 964 // LR: return address. |
966 // SP+1: receiver. | 965 // SP+1: receiver. |
967 // SP+0: value. | 966 // SP+0: value. |
968 // Sequence node has one store node and one return NULL node. | 967 // Sequence node has one store node and one return NULL node. |
969 __ Comment("Inlined Setter"); | 968 __ Comment("Inlined Setter"); |
970 __ ldr(R0, Address(SP, 1 * kWordSize)); // Receiver. | 969 __ ldr(R0, Address(SP, 1 * kWordSize)); // Receiver. |
971 __ ldr(R1, Address(SP, 0 * kWordSize)); // Value. | 970 __ ldr(R1, Address(SP, 0 * kWordSize)); // Value. |
972 __ StoreIntoObjectOffset(R0, offset, R1); | 971 __ StoreIntoObjectOffset(R0, offset, R1); |
973 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); | 972 __ LoadObject(R0, Object::null_object()); |
974 __ Ret(); | 973 __ Ret(); |
975 } | 974 } |
976 | 975 |
977 | 976 |
978 void FlowGraphCompiler::EmitFrameEntry() { | 977 void FlowGraphCompiler::EmitFrameEntry() { |
979 const Function& function = parsed_function().function(); | 978 const Function& function = parsed_function().function(); |
980 if (CanOptimizeFunction() && | 979 if (CanOptimizeFunction() && |
981 function.IsOptimizable() && | 980 function.IsOptimizable() && |
982 (!is_optimizing() || may_reoptimize())) { | 981 (!is_optimizing() || may_reoptimize())) { |
983 const Register function_reg = R6; | 982 const Register function_reg = R6; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 | 1096 |
1098 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1097 // In unoptimized code, initialize (non-argument) stack allocated slots to |
1099 // null. | 1098 // null. |
1100 if (!is_optimizing()) { | 1099 if (!is_optimizing()) { |
1101 ASSERT(num_locals > 0); // There is always at least context_var. | 1100 ASSERT(num_locals > 0); // There is always at least context_var. |
1102 __ Comment("Initialize spill slots"); | 1101 __ Comment("Initialize spill slots"); |
1103 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1102 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
1104 const intptr_t context_index = | 1103 const intptr_t context_index = |
1105 parsed_function().current_context_var()->index(); | 1104 parsed_function().current_context_var()->index(); |
1106 if (num_locals > 1) { | 1105 if (num_locals > 1) { |
1107 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); | 1106 __ LoadObject(R0, Object::null_object()); |
1108 } | 1107 } |
1109 for (intptr_t i = 0; i < num_locals; ++i) { | 1108 for (intptr_t i = 0; i < num_locals; ++i) { |
1110 // Subtract index i (locals lie at lower addresses than FP). | 1109 // Subtract index i (locals lie at lower addresses than FP). |
1111 if (((slot_base - i) == context_index)) { | 1110 if (((slot_base - i) == context_index)) { |
1112 if (function.IsClosureFunction()) { | 1111 if (function.IsClosureFunction()) { |
1113 __ StoreToOffset(kWord, CTX, FP, (slot_base - i) * kWordSize); | 1112 __ StoreToOffset(kWord, CTX, FP, (slot_base - i) * kWordSize); |
1114 } else { | 1113 } else { |
1115 const Context& empty_context = Context::ZoneHandle( | 1114 const Context& empty_context = Context::ZoneHandle( |
1116 zone(), isolate()->object_store()->empty_context()); | 1115 zone(), isolate()->object_store()->empty_context()); |
1117 __ LoadObject(R1, empty_context); | 1116 __ LoadObject(R1, empty_context); |
(...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 DRegister dreg = EvenDRegisterOf(reg); | 1896 DRegister dreg = EvenDRegisterOf(reg); |
1898 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1897 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
1899 } | 1898 } |
1900 | 1899 |
1901 | 1900 |
1902 #undef __ | 1901 #undef __ |
1903 | 1902 |
1904 } // namespace dart | 1903 } // namespace dart |
1905 | 1904 |
1906 #endif // defined TARGET_ARCH_ARM | 1905 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |