OLD | NEW |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dartino 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 #if defined(DARTINO_TARGET_ARM) | 5 #if defined(DARTINO_TARGET_ARM) |
6 | 6 |
7 #include "src/shared/bytecodes.h" | 7 #include "src/shared/bytecodes.h" |
8 #include "src/shared/names.h" | 8 #include "src/shared/names.h" |
9 #include "src/shared/selectors.h" | 9 #include "src/shared/selectors.h" |
10 | 10 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 #undef V | 79 #undef V |
80 } | 80 } |
81 | 81 |
82 class InterpreterGeneratorARM : public InterpreterGenerator { | 82 class InterpreterGeneratorARM : public InterpreterGenerator { |
83 public: | 83 public: |
84 explicit InterpreterGeneratorARM(Assembler* assembler) | 84 explicit InterpreterGeneratorARM(Assembler* assembler) |
85 : InterpreterGenerator(assembler), spill_size_(-1) {} | 85 : InterpreterGenerator(assembler), spill_size_(-1) {} |
86 | 86 |
87 // Registers | 87 // Registers |
88 // --------- | 88 // --------- |
89 // r4: current process | 89 // R4: current process |
90 // r5: bytecode pointer | 90 // R5: bytecode pointer |
91 // r6: stack pointer (top) | 91 // R6: stack pointer (top) |
92 // r8: null | 92 // R8: null |
93 // r10: true | 93 // R10: program |
94 // r11: false | 94 // R11: dispatch table |
95 | 95 |
96 virtual void GeneratePrologue(); | 96 virtual void GeneratePrologue(); |
97 virtual void GenerateEpilogue(); | 97 virtual void GenerateEpilogue(); |
98 | 98 |
99 virtual void GenerateMethodEntry(); | 99 virtual void GenerateMethodEntry(); |
100 | 100 |
101 virtual void GenerateBytecodePrologue(const char* name); | 101 virtual void GenerateBytecodePrologue(const char* name); |
102 virtual void GenerateDebugAtBytecode(); | 102 virtual void GenerateDebugAtBytecode(); |
103 | 103 |
104 virtual void DoLoadLocal0(); | 104 virtual void DoLoadLocal0(); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 private: | 232 private: |
233 Label done_; | 233 Label done_; |
234 Label done_state_saved_; | 234 Label done_state_saved_; |
235 Label check_stack_overflow_; | 235 Label check_stack_overflow_; |
236 Label check_stack_overflow_0_; | 236 Label check_stack_overflow_0_; |
237 Label gc_; | 237 Label gc_; |
238 Label intrinsic_failure_; | 238 Label intrinsic_failure_; |
239 Label interpreter_entry_; | 239 Label interpreter_entry_; |
240 int spill_size_; | 240 int spill_size_; |
241 | 241 |
| 242 static const int kFalseOffset = 8; |
| 243 static const int kTrueOffset = 16; |
| 244 |
242 void LoadLocal(Register reg, int index); | 245 void LoadLocal(Register reg, int index); |
243 void StoreLocal(Register reg, int index); | 246 void StoreLocal(Register reg, int index); |
244 | 247 |
245 void Push(Register reg); | 248 void Push(Register reg); |
246 void Pop(Register reg); | 249 void Pop(Register reg); |
247 void Drop(int n); | 250 void Drop(int n); |
248 void Drop(Register reg); | 251 void Drop(Register reg); |
249 void DropNAndSetTop(int dropping_slots, Register reg); | 252 void DropNAndSetTop(int dropping_slots, Register reg); |
250 | 253 |
251 void LoadFramePointer(Register reg); | 254 void LoadFramePointer(Register reg); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 void InvokeBitXor(const char* fallback); | 286 void InvokeBitXor(const char* fallback); |
284 void InvokeBitShr(const char* fallback); | 287 void InvokeBitShr(const char* fallback); |
285 void InvokeBitShl(const char* fallback); | 288 void InvokeBitShl(const char* fallback); |
286 | 289 |
287 void InvokeMethodUnfold(bool test); | 290 void InvokeMethodUnfold(bool test); |
288 void InvokeMethod(bool test); | 291 void InvokeMethod(bool test); |
289 | 292 |
290 void InvokeNative(bool yield, bool safepoint); | 293 void InvokeNative(bool yield, bool safepoint); |
291 void InvokeStatic(); | 294 void InvokeStatic(); |
292 | 295 |
293 void ConditionalStore(Register reg_if_eq, Register reg_if_ne, | 296 void AddIf(Condition cond, Register reg, int immediate); |
294 const Address& address); | 297 void ToBoolean(Condition cond, Register reg); |
| 298 void LoadFalse(Register reg); |
| 299 void LoadTrue(Register reg); |
295 | 300 |
296 void CheckStackOverflow(int size); | 301 void CheckStackOverflow(int size); |
297 | 302 |
298 void Dispatch(int size); | 303 void Dispatch(int size); |
299 | 304 |
300 void SaveState(Label* resume); | 305 void SaveState(Label* resume); |
301 void RestoreState(); | 306 void RestoreState(); |
302 | 307 |
303 static int ComputeStackPadding(int reserved, int extra) { | 308 static int ComputeStackPadding(int reserved, int extra) { |
304 const int kAlignment = 8; | 309 const int kAlignment = 8; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 __ b(NE, &overflow); | 401 __ b(NE, &overflow); |
397 __ mov(R0, Immediate(Interpreter::kBreakpoint)); | 402 __ mov(R0, Immediate(Interpreter::kBreakpoint)); |
398 __ b(&done_); | 403 __ b(&done_); |
399 | 404 |
400 __ Bind(&stay_fast); | 405 __ Bind(&stay_fast); |
401 Dispatch(0); | 406 Dispatch(0); |
402 | 407 |
403 __ Bind(&overflow); | 408 __ Bind(&overflow); |
404 Label throw_resume; | 409 Label throw_resume; |
405 SaveState(&throw_resume); | 410 SaveState(&throw_resume); |
406 __ ldr(R7, Address(R4, Process::kProgramOffset)); | 411 __ ldr(R7, Address(R10, Program::kStackOverflowErrorOffset)); |
407 __ ldr(R7, Address(R7, Program::kStackOverflowErrorOffset)); | |
408 DoThrowAfterSaveState(&throw_resume); | 412 DoThrowAfterSaveState(&throw_resume); |
409 | 413 |
410 // Intrinsic failure: Just invoke the method. | 414 // Intrinsic failure: Just invoke the method. |
411 __ Bind(&intrinsic_failure_); | 415 __ Bind(&intrinsic_failure_); |
412 __ b("InterpreterMethodEntry"); | 416 __ b("InterpreterMethodEntry"); |
413 } | 417 } |
414 | 418 |
415 void InterpreterGeneratorARM::GenerateMethodEntry() { | 419 void InterpreterGeneratorARM::GenerateMethodEntry() { |
416 __ SwitchToText(); | 420 __ SwitchToText(); |
417 __ AlignToPowerOfTwo(3); | 421 __ AlignToPowerOfTwo(3); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 | 637 |
634 Dispatch(kStoreFieldWideLength); | 638 Dispatch(kStoreFieldWideLength); |
635 } | 639 } |
636 | 640 |
637 void InterpreterGeneratorARM::DoLoadLiteralNull() { | 641 void InterpreterGeneratorARM::DoLoadLiteralNull() { |
638 Push(R8); | 642 Push(R8); |
639 Dispatch(kLoadLiteralNullLength); | 643 Dispatch(kLoadLiteralNullLength); |
640 } | 644 } |
641 | 645 |
642 void InterpreterGeneratorARM::DoLoadLiteralTrue() { | 646 void InterpreterGeneratorARM::DoLoadLiteralTrue() { |
643 Push(R10); | 647 LoadTrue(R2); |
| 648 Push(R2); |
644 Dispatch(kLoadLiteralTrueLength); | 649 Dispatch(kLoadLiteralTrueLength); |
645 } | 650 } |
646 | 651 |
647 void InterpreterGeneratorARM::DoLoadLiteralFalse() { | 652 void InterpreterGeneratorARM::DoLoadLiteralFalse() { |
648 Push(R11); | 653 LoadFalse(R2); |
| 654 Push(R2); |
649 Dispatch(kLoadLiteralFalseLength); | 655 Dispatch(kLoadLiteralFalseLength); |
650 } | 656 } |
651 | 657 |
652 void InterpreterGeneratorARM::DoLoadLiteral0() { | 658 void InterpreterGeneratorARM::DoLoadLiteral0() { |
653 __ mov(R0, Immediate(reinterpret_cast<int32_t>(Smi::FromWord(0)))); | 659 __ mov(R0, Immediate(reinterpret_cast<int32_t>(Smi::FromWord(0)))); |
654 Push(R0); | 660 Push(R0); |
655 Dispatch(kLoadLiteral0Length); | 661 Dispatch(kLoadLiteral0Length); |
656 } | 662 } |
657 | 663 |
658 void InterpreterGeneratorARM::DoLoadLiteral1() { | 664 void InterpreterGeneratorARM::DoLoadLiteral1() { |
(...skipping 19 matching lines...) Expand all Loading... |
678 } | 684 } |
679 | 685 |
680 void InterpreterGeneratorARM::DoInvokeMethodUnfold() { | 686 void InterpreterGeneratorARM::DoInvokeMethodUnfold() { |
681 InvokeMethodUnfold(false); | 687 InvokeMethodUnfold(false); |
682 } | 688 } |
683 | 689 |
684 void InterpreterGeneratorARM::DoInvokeMethod() { InvokeMethod(false); } | 690 void InterpreterGeneratorARM::DoInvokeMethod() { InvokeMethod(false); } |
685 | 691 |
686 void InterpreterGeneratorARM::DoInvokeNoSuchMethod() { | 692 void InterpreterGeneratorARM::DoInvokeNoSuchMethod() { |
687 // Use the noSuchMethod entry from entry zero of the virtual table. | 693 // Use the noSuchMethod entry from entry zero of the virtual table. |
688 __ ldr(R1, Address(R4, Process::kProgramOffset)); | 694 __ ldr(R1, Address(R10, Program::kDispatchTableOffset)); |
689 __ ldr(R1, Address(R1, Program::kDispatchTableOffset)); | |
690 __ ldr(R1, Address(R1, Array::kSize - HeapObject::kTag)); | 695 __ ldr(R1, Address(R1, Array::kSize - HeapObject::kTag)); |
691 | 696 |
692 // Load the function. | 697 // Load the function. |
693 __ ldr(R0, | 698 __ ldr(R0, |
694 Address(R1, DispatchTableEntry::kTargetOffset - HeapObject::kTag)); | 699 Address(R1, DispatchTableEntry::kTargetOffset - HeapObject::kTag)); |
695 | 700 |
696 SaveByteCodePointer(R2); | 701 SaveByteCodePointer(R2); |
697 __ bl("InterpreterMethodEntry"); | 702 __ bl("InterpreterMethodEntry"); |
698 RestoreByteCodePointer(R2); | 703 RestoreByteCodePointer(R2); |
699 | 704 |
700 __ ldr(R7, Address(R5, 1)); | 705 __ ldr(R7, Address(R5, 1)); |
701 // Compute the arity from the selector. | 706 // Compute the arity from the selector. |
702 ASSERT(Selector::ArityField::shift() == 0); | 707 ASSERT(Selector::ArityField::shift() == 0); |
703 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); | 708 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); |
704 | 709 |
705 Drop(R2); | 710 Drop(R2); |
706 | 711 |
707 StoreLocal(R0, 0); | 712 StoreLocal(R0, 0); |
708 Dispatch(kInvokeNoSuchMethodLength); | 713 Dispatch(kInvokeNoSuchMethodLength); |
709 } | 714 } |
710 | 715 |
711 void InterpreterGeneratorARM::DoInvokeTestNoSuchMethod() { | 716 void InterpreterGeneratorARM::DoInvokeTestNoSuchMethod() { |
712 StoreLocal(R11, 0); | 717 LoadFalse(R2); |
| 718 StoreLocal(R2, 0); |
713 Dispatch(kInvokeTestNoSuchMethodLength); | 719 Dispatch(kInvokeTestNoSuchMethodLength); |
714 } | 720 } |
715 | 721 |
716 void InterpreterGeneratorARM::DoInvokeTestUnfold() { InvokeMethodUnfold(true); } | 722 void InterpreterGeneratorARM::DoInvokeTestUnfold() { InvokeMethodUnfold(true); } |
717 | 723 |
718 void InterpreterGeneratorARM::DoInvokeTest() { InvokeMethod(true); } | 724 void InterpreterGeneratorARM::DoInvokeTest() { InvokeMethod(true); } |
719 | 725 |
720 void InterpreterGeneratorARM::DoInvokeStatic() { InvokeStatic(); } | 726 void InterpreterGeneratorARM::DoInvokeStatic() { InvokeStatic(); } |
721 | 727 |
722 void InterpreterGeneratorARM::DoInvokeFactory() { InvokeStatic(); } | 728 void InterpreterGeneratorARM::DoInvokeFactory() { InvokeStatic(); } |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 | 968 |
963 void InterpreterGeneratorARM::DoBranchWide() { | 969 void InterpreterGeneratorARM::DoBranchWide() { |
964 __ ldr(R0, Address(R5, 1)); | 970 __ ldr(R0, Address(R5, 1)); |
965 __ adds(R5, R5, R0); | 971 __ adds(R5, R5, R0); |
966 Dispatch(0); | 972 Dispatch(0); |
967 } | 973 } |
968 | 974 |
969 void InterpreterGeneratorARM::DoBranchIfTrueWide() { | 975 void InterpreterGeneratorARM::DoBranchIfTrueWide() { |
970 Label branch; | 976 Label branch; |
971 Pop(R7); | 977 Pop(R7); |
972 __ cmp(R7, R10); | 978 LoadTrue(R2); |
| 979 __ cmp(R7, R2); |
973 __ b(EQ, &branch); | 980 __ b(EQ, &branch); |
974 Dispatch(kBranchIfTrueWideLength); | 981 Dispatch(kBranchIfTrueWideLength); |
975 | 982 |
976 __ Bind(&branch); | 983 __ Bind(&branch); |
977 __ ldr(R0, Address(R5, 1)); | 984 __ ldr(R0, Address(R5, 1)); |
978 __ adds(R5, R5, R0); | 985 __ adds(R5, R5, R0); |
979 Dispatch(0); | 986 Dispatch(0); |
980 } | 987 } |
981 | 988 |
982 void InterpreterGeneratorARM::DoBranchIfFalseWide() { | 989 void InterpreterGeneratorARM::DoBranchIfFalseWide() { |
983 Label branch; | 990 Label branch; |
984 Pop(R7); | 991 Pop(R7); |
985 __ cmp(R7, R10); | 992 LoadTrue(R2); |
| 993 __ cmp(R7, R2); |
986 __ b(NE, &branch); | 994 __ b(NE, &branch); |
987 Dispatch(kBranchIfFalseWideLength); | 995 Dispatch(kBranchIfFalseWideLength); |
988 | 996 |
989 __ Bind(&branch); | 997 __ Bind(&branch); |
990 __ ldr(R0, Address(R5, 1)); | 998 __ ldr(R0, Address(R5, 1)); |
991 __ adds(R5, R5, R0); | 999 __ adds(R5, R5, R0); |
992 Dispatch(0); | 1000 Dispatch(0); |
993 } | 1001 } |
994 | 1002 |
995 void InterpreterGeneratorARM::DoBranchBack() { | 1003 void InterpreterGeneratorARM::DoBranchBack() { |
996 CheckStackOverflow(0); | 1004 CheckStackOverflow(0); |
997 __ ldrb(R0, Address(R5, 1)); | 1005 __ ldrb(R0, Address(R5, 1)); |
998 __ subs(R5, R5, R0); | 1006 __ subs(R5, R5, R0); |
999 Dispatch(0); | 1007 Dispatch(0); |
1000 } | 1008 } |
1001 | 1009 |
1002 void InterpreterGeneratorARM::DoBranchBackIfTrue() { | 1010 void InterpreterGeneratorARM::DoBranchBackIfTrue() { |
1003 CheckStackOverflow(0); | 1011 CheckStackOverflow(0); |
1004 | 1012 |
1005 Label branch; | 1013 Label branch; |
1006 Pop(R1); | 1014 Pop(R1); |
1007 __ cmp(R1, R10); | 1015 LoadTrue(R2); |
| 1016 __ cmp(R1, R2); |
1008 __ b(EQ, &branch); | 1017 __ b(EQ, &branch); |
1009 Dispatch(kBranchBackIfTrueLength); | 1018 Dispatch(kBranchBackIfTrueLength); |
1010 | 1019 |
1011 __ Bind(&branch); | 1020 __ Bind(&branch); |
1012 __ ldrb(R0, Address(R5, 1)); | 1021 __ ldrb(R0, Address(R5, 1)); |
1013 __ subs(R5, R5, R0); | 1022 __ subs(R5, R5, R0); |
1014 Dispatch(0); | 1023 Dispatch(0); |
1015 } | 1024 } |
1016 | 1025 |
1017 void InterpreterGeneratorARM::DoBranchBackIfFalse() { | 1026 void InterpreterGeneratorARM::DoBranchBackIfFalse() { |
1018 CheckStackOverflow(0); | 1027 CheckStackOverflow(0); |
1019 | 1028 |
1020 Label branch; | 1029 Label branch; |
1021 Pop(R1); | 1030 Pop(R1); |
1022 __ cmp(R1, R10); | 1031 LoadTrue(R2); |
| 1032 __ cmp(R1, R2); |
1023 __ b(NE, &branch); | 1033 __ b(NE, &branch); |
1024 Dispatch(kBranchBackIfFalseLength); | 1034 Dispatch(kBranchBackIfFalseLength); |
1025 | 1035 |
1026 __ Bind(&branch); | 1036 __ Bind(&branch); |
1027 __ ldrb(R0, Address(R5, 1)); | 1037 __ ldrb(R0, Address(R5, 1)); |
1028 __ subs(R5, R5, R0); | 1038 __ subs(R5, R5, R0); |
1029 Dispatch(0); | 1039 Dispatch(0); |
1030 } | 1040 } |
1031 | 1041 |
1032 void InterpreterGeneratorARM::DoBranchBackWide() { | 1042 void InterpreterGeneratorARM::DoBranchBackWide() { |
1033 CheckStackOverflow(0); | 1043 CheckStackOverflow(0); |
1034 __ ldr(R0, Address(R5, 1)); | 1044 __ ldr(R0, Address(R5, 1)); |
1035 __ subs(R5, R5, R0); | 1045 __ subs(R5, R5, R0); |
1036 Dispatch(0); | 1046 Dispatch(0); |
1037 } | 1047 } |
1038 | 1048 |
1039 void InterpreterGeneratorARM::DoBranchBackIfTrueWide() { | 1049 void InterpreterGeneratorARM::DoBranchBackIfTrueWide() { |
1040 CheckStackOverflow(0); | 1050 CheckStackOverflow(0); |
1041 | 1051 |
1042 Label branch; | 1052 Label branch; |
1043 Pop(R1); | 1053 Pop(R1); |
1044 __ cmp(R10, R1); | 1054 LoadTrue(R2); |
| 1055 __ cmp(R2, R1); |
1045 __ b(EQ, &branch); | 1056 __ b(EQ, &branch); |
1046 Dispatch(kBranchBackIfTrueWideLength); | 1057 Dispatch(kBranchBackIfTrueWideLength); |
1047 | 1058 |
1048 __ Bind(&branch); | 1059 __ Bind(&branch); |
1049 __ ldr(R0, Address(R5, 1)); | 1060 __ ldr(R0, Address(R5, 1)); |
1050 __ subs(R5, R5, R0); | 1061 __ subs(R5, R5, R0); |
1051 Dispatch(0); | 1062 Dispatch(0); |
1052 } | 1063 } |
1053 | 1064 |
1054 void InterpreterGeneratorARM::DoBranchBackIfFalseWide() { | 1065 void InterpreterGeneratorARM::DoBranchBackIfFalseWide() { |
1055 CheckStackOverflow(0); | 1066 CheckStackOverflow(0); |
1056 | 1067 |
1057 Label branch; | 1068 Label branch; |
1058 Pop(R1); | 1069 Pop(R1); |
1059 __ cmp(R10, R1); | 1070 LoadTrue(R2); |
| 1071 __ cmp(R2, R1); |
1060 __ b(NE, &branch); | 1072 __ b(NE, &branch); |
1061 Dispatch(kBranchBackIfTrueWideLength); | 1073 Dispatch(kBranchBackIfTrueWideLength); |
1062 | 1074 |
1063 __ Bind(&branch); | 1075 __ Bind(&branch); |
1064 __ ldr(R0, Address(R5, 1)); | 1076 __ ldr(R0, Address(R5, 1)); |
1065 __ subs(R5, R5, R0); | 1077 __ subs(R5, R5, R0); |
1066 Dispatch(0); | 1078 Dispatch(0); |
1067 } | 1079 } |
1068 | 1080 |
1069 void InterpreterGeneratorARM::DoPopAndBranchWide() { | 1081 void InterpreterGeneratorARM::DoPopAndBranchWide() { |
(...skipping 26 matching lines...) Expand all Loading... |
1096 __ bl("HandleAllocateBoxed"); | 1108 __ bl("HandleAllocateBoxed"); |
1097 __ and_(R1, R0, Immediate(Failure::kTagMask | Failure::kTypeMask)); | 1109 __ and_(R1, R0, Immediate(Failure::kTagMask | Failure::kTypeMask)); |
1098 __ cmp(R1, Immediate(Failure::kTag)); | 1110 __ cmp(R1, Immediate(Failure::kTag)); |
1099 __ b(EQ, &gc_); | 1111 __ b(EQ, &gc_); |
1100 StoreLocal(R0, 0); | 1112 StoreLocal(R0, 0); |
1101 Dispatch(kAllocateBoxedLength); | 1113 Dispatch(kAllocateBoxedLength); |
1102 } | 1114 } |
1103 | 1115 |
1104 void InterpreterGeneratorARM::DoNegate() { | 1116 void InterpreterGeneratorARM::DoNegate() { |
1105 LoadLocal(R1, 0); | 1117 LoadLocal(R1, 0); |
1106 __ cmp(R1, R10); | 1118 LoadTrue(R2); |
1107 ConditionalStore(R11, R10, Address(R6, 0)); | 1119 __ cmp(R1, R2); |
| 1120 AddIf(EQ, R2, kFalseOffset - kTrueOffset); |
| 1121 StoreLocal(R2, 0); |
1108 Dispatch(kNegateLength); | 1122 Dispatch(kNegateLength); |
1109 } | 1123 } |
1110 | 1124 |
1111 void InterpreterGeneratorARM::DoStackOverflowCheck() { | 1125 void InterpreterGeneratorARM::DoStackOverflowCheck() { |
1112 __ ldr(R0, Address(R5, 1)); | 1126 __ ldr(R0, Address(R5, 1)); |
1113 __ ldr(R1, Address(R4, Process::kStackLimitOffset)); | 1127 __ ldr(R1, Address(R4, Process::kStackLimitOffset)); |
1114 __ sub(R3, R6, Operand(R0, TIMES_WORD_SIZE)); | 1128 __ sub(R3, R6, Operand(R0, TIMES_WORD_SIZE)); |
1115 __ cmp(R3, R1); | 1129 __ cmp(R3, R1); |
1116 __ b(LS, &check_stack_overflow_); | 1130 __ b(LS, &check_stack_overflow_); |
1117 Dispatch(kStackOverflowCheckLength); | 1131 Dispatch(kStackOverflowCheckLength); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1246 int type_field_shift = InstanceFormat::TypeField::shift(); | 1260 int type_field_shift = InstanceFormat::TypeField::shift(); |
1247 | 1261 |
1248 __ and_(R2, R2, Immediate(InstanceFormat::TypeField::mask())); | 1262 __ and_(R2, R2, Immediate(InstanceFormat::TypeField::mask())); |
1249 __ cmp(R2, Immediate(double_type << type_field_shift)); | 1263 __ cmp(R2, Immediate(double_type << type_field_shift)); |
1250 __ b(EQ, &bail_out); | 1264 __ b(EQ, &bail_out); |
1251 __ cmp(R2, Immediate(large_integer_type << type_field_shift)); | 1265 __ cmp(R2, Immediate(large_integer_type << type_field_shift)); |
1252 __ b(EQ, &bail_out); | 1266 __ b(EQ, &bail_out); |
1253 | 1267 |
1254 __ Bind(&fast_case); | 1268 __ Bind(&fast_case); |
1255 __ cmp(R1, R0); | 1269 __ cmp(R1, R0); |
1256 ConditionalStore(R10, R11, Address(R6, kWordSize)); | 1270 ToBoolean(EQ, R2); |
| 1271 StoreLocal(R2, 1); |
1257 Drop(1); | 1272 Drop(1); |
1258 Dispatch(kIdenticalLength); | 1273 Dispatch(kIdenticalLength); |
1259 | 1274 |
1260 __ Bind(&bail_out); | 1275 __ Bind(&bail_out); |
1261 __ mov(R2, R0); | 1276 __ mov(R2, R0); |
1262 __ mov(R0, R4); | 1277 __ mov(R0, R4); |
1263 __ bl("HandleIdentical"); | 1278 __ bl("HandleIdentical"); |
1264 DropNAndSetTop(1, R0); | 1279 DropNAndSetTop(1, R0); |
1265 Dispatch(kIdenticalLength); | 1280 Dispatch(kIdenticalLength); |
1266 } | 1281 } |
1267 | 1282 |
1268 void InterpreterGeneratorARM::DoIdenticalNonNumeric() { | 1283 void InterpreterGeneratorARM::DoIdenticalNonNumeric() { |
1269 LoadLocal(R0, 0); | 1284 LoadLocal(R0, 0); |
1270 LoadLocal(R1, 1); | 1285 LoadLocal(R1, 1); |
1271 __ cmp(R0, R1); | 1286 __ cmp(R0, R1); |
1272 ConditionalStore(R10, R11, Address(R6, kWordSize)); | 1287 ToBoolean(EQ, R2); |
| 1288 StoreLocal(R2, 1); |
1273 Drop(1); | 1289 Drop(1); |
1274 Dispatch(kIdenticalNonNumericLength); | 1290 Dispatch(kIdenticalNonNumericLength); |
1275 } | 1291 } |
1276 | 1292 |
1277 void InterpreterGeneratorARM::DoEnterNoSuchMethod() { | 1293 void InterpreterGeneratorARM::DoEnterNoSuchMethod() { |
1278 SaveState(&interpreter_entry_); | 1294 SaveState(&interpreter_entry_); |
1279 __ mov(R0, R4); | 1295 __ mov(R0, R4); |
1280 __ bl("HandleEnterNoSuchMethod"); | 1296 __ bl("HandleEnterNoSuchMethod"); |
1281 RestoreState(); | 1297 RestoreState(); |
1282 } | 1298 } |
(...skipping 21 matching lines...) Expand all Loading... |
1304 Pop(LR); | 1320 Pop(LR); |
1305 __ mov(PC, LR); | 1321 __ mov(PC, LR); |
1306 } | 1322 } |
1307 | 1323 |
1308 void InterpreterGeneratorARM::DoMethodEnd() { __ bkpt(); } | 1324 void InterpreterGeneratorARM::DoMethodEnd() { __ bkpt(); } |
1309 | 1325 |
1310 void InterpreterGeneratorARM::DoIntrinsicObjectEquals() { | 1326 void InterpreterGeneratorARM::DoIntrinsicObjectEquals() { |
1311 LoadLocal(R0, 0); | 1327 LoadLocal(R0, 0); |
1312 LoadLocal(R1, 1); | 1328 LoadLocal(R1, 1); |
1313 __ cmp(R0, R1); | 1329 __ cmp(R0, R1); |
1314 ConditionalStore(R10, R11, Address(R6, -kWordSize)); | 1330 ToBoolean(EQ, R2); |
| 1331 StoreLocal(R2, -1); |
1315 Drop(1); | 1332 Drop(1); |
1316 Dispatch(kInvokeMethodLength); | 1333 Dispatch(kInvokeMethodLength); |
1317 } | 1334 } |
1318 | 1335 |
1319 void InterpreterGeneratorARM::DoIntrinsicGetField() { | 1336 void InterpreterGeneratorARM::DoIntrinsicGetField() { |
1320 __ ldrb(R1, Address(R0, 2 + Function::kSize - HeapObject::kTag)); | 1337 __ ldrb(R1, Address(R0, 2 + Function::kSize - HeapObject::kTag)); |
1321 LoadLocal(R0, 0); | 1338 LoadLocal(R0, 0); |
1322 __ adds(R0, R0, Immediate(Instance::kSize - HeapObject::kTag)); | 1339 __ adds(R0, R0, Immediate(Instance::kSize - HeapObject::kTag)); |
1323 __ ldr(R0, Address(R0, Operand(R1, TIMES_WORD_SIZE))); | 1340 __ ldr(R0, Address(R0, Operand(R1, TIMES_WORD_SIZE))); |
1324 | 1341 |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1570 __ b(NE, &hit); | 1587 __ b(NE, &hit); |
1571 __ ldr(R0, "InterpreterMethodEntry"); | 1588 __ ldr(R0, "InterpreterMethodEntry"); |
1572 __ Bind(&hit); | 1589 __ Bind(&hit); |
1573 } | 1590 } |
1574 | 1591 |
1575 if (test) { | 1592 if (test) { |
1576 // Materialize either true or false depending on whether or not | 1593 // Materialize either true or false depending on whether or not |
1577 // we've found a target method. | 1594 // we've found a target method. |
1578 Label found; | 1595 Label found; |
1579 __ tst(R0, R0); | 1596 __ tst(R0, R0); |
1580 ConditionalStore(R11, R10, Address(R6, 0)); | 1597 ToBoolean(EQ, R2); |
| 1598 StoreLocal(R2, 0); |
1581 Dispatch(kInvokeTestUnfoldLength); | 1599 Dispatch(kInvokeTestUnfoldLength); |
1582 } else { | 1600 } else { |
1583 SaveByteCodePointer(R2); | 1601 SaveByteCodePointer(R2); |
1584 __ bl("InterpreterMethodEntry"); | 1602 __ bl("InterpreterMethodEntry"); |
1585 RestoreByteCodePointer(R2); | 1603 RestoreByteCodePointer(R2); |
1586 | 1604 |
1587 __ ldr(R7, Address(R5, 1)); | 1605 __ ldr(R7, Address(R5, 1)); |
1588 // Compute the arity from the selector. | 1606 // Compute the arity from the selector. |
1589 ASSERT(Selector::ArityField::shift() == 0); | 1607 ASSERT(Selector::ArityField::shift() == 0); |
1590 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); | 1608 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); |
1591 | 1609 |
1592 Drop(R2); | 1610 Drop(R2); |
1593 | 1611 |
1594 StoreLocal(R0, 0); | 1612 StoreLocal(R0, 0); |
1595 Dispatch(kInvokeMethodUnfoldLength); | 1613 Dispatch(kInvokeMethodUnfoldLength); |
1596 } | 1614 } |
1597 | 1615 |
1598 __ Bind(&smi); | 1616 __ Bind(&smi); |
1599 __ ldr(R3, Address(R4, Process::kProgramOffset)); | 1617 __ ldr(R2, Address(R10, Program::kSmiClassOffset)); |
1600 __ ldr(R2, Address(R3, Program::kSmiClassOffset)); | |
1601 __ b(&probe); | 1618 __ b(&probe); |
1602 | 1619 |
1603 // We didn't find a valid entry in primary lookup cache. | 1620 // We didn't find a valid entry in primary lookup cache. |
1604 __ Bind(&miss); | 1621 __ Bind(&miss); |
1605 // Arguments: | 1622 // Arguments: |
1606 // - r0: process | 1623 // - r0: process |
1607 // - r1: primary cache entry | 1624 // - r1: primary cache entry |
1608 // - r2: class (already in r2) | 1625 // - r2: class (already in r2) |
1609 // - r3: selector | 1626 // - r3: selector |
1610 __ mov(R1, R0); | 1627 __ mov(R1, R0); |
1611 __ mov(R0, R4); | 1628 __ mov(R0, R4); |
1612 __ mov(R3, R7); | 1629 __ mov(R3, R7); |
1613 __ bl("HandleLookupEntry"); | 1630 __ bl("HandleLookupEntry"); |
1614 __ b(&finish); | 1631 __ b(&finish); |
1615 } | 1632 } |
1616 | 1633 |
1617 void InterpreterGeneratorARM::InvokeMethod(bool test) { | 1634 void InterpreterGeneratorARM::InvokeMethod(bool test) { |
1618 // Get the selector from the bytecodes. | 1635 // Get the selector from the bytecodes. |
1619 __ ldr(R7, Address(R5, 1)); | 1636 __ ldr(R7, Address(R5, 1)); |
1620 | 1637 |
1621 // Fetch the virtual table from the program. | 1638 // Fetch the virtual table from the program. |
1622 __ ldr(R1, Address(R4, Process::kProgramOffset)); | 1639 __ ldr(R1, Address(R10, Program::kDispatchTableOffset)); |
1623 __ ldr(R1, Address(R1, Program::kDispatchTableOffset)); | |
1624 | 1640 |
1625 if (!test) { | 1641 if (!test) { |
1626 // Compute the arity from the selector. | 1642 // Compute the arity from the selector. |
1627 ASSERT(Selector::ArityField::shift() == 0); | 1643 ASSERT(Selector::ArityField::shift() == 0); |
1628 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); | 1644 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); |
1629 } | 1645 } |
1630 | 1646 |
1631 // Compute the selector offset (smi tagged) from the selector. | 1647 // Compute the selector offset (smi tagged) from the selector. |
1632 __ LoadInt(R9, Selector::IdField::mask()); | 1648 __ LoadInt(R9, Selector::IdField::mask()); |
1633 __ and_(R7, R7, R9); | 1649 __ and_(R7, R7, R9); |
(...skipping 29 matching lines...) Expand all Loading... |
1663 // we used to find it. | 1679 // we used to find it. |
1664 Label invalid; | 1680 Label invalid; |
1665 __ ldr(R3, Address(R1, DispatchTableEntry::kOffsetOffset - HeapObject::kTag)); | 1681 __ ldr(R3, Address(R1, DispatchTableEntry::kOffsetOffset - HeapObject::kTag)); |
1666 __ cmp(R7, R3); | 1682 __ cmp(R7, R3); |
1667 __ b(NE, &invalid); | 1683 __ b(NE, &invalid); |
1668 | 1684 |
1669 // Load the target and the intrinsic from the entry. | 1685 // Load the target and the intrinsic from the entry. |
1670 Label validated, intrinsified; | 1686 Label validated, intrinsified; |
1671 if (test) { | 1687 if (test) { |
1672 // Valid entry: The answer is true. | 1688 // Valid entry: The answer is true. |
1673 StoreLocal(R10, 0); | 1689 LoadTrue(R2); |
| 1690 StoreLocal(R2, 0); |
1674 Dispatch(kInvokeTestLength); | 1691 Dispatch(kInvokeTestLength); |
1675 } else { | 1692 } else { |
1676 __ Bind(&validated); | 1693 __ Bind(&validated); |
1677 | 1694 |
1678 __ ldr(R0, | 1695 __ ldr(R0, |
1679 Address(R1, DispatchTableEntry::kTargetOffset - HeapObject::kTag)); | 1696 Address(R1, DispatchTableEntry::kTargetOffset - HeapObject::kTag)); |
1680 | 1697 |
1681 SaveByteCodePointer(R2); | 1698 SaveByteCodePointer(R2); |
1682 __ ldr(R1, | 1699 __ ldr(R1, |
1683 Address(R1, DispatchTableEntry::kCodeOffset - HeapObject::kTag)); | 1700 Address(R1, DispatchTableEntry::kCodeOffset - HeapObject::kTag)); |
1684 __ blx(R1); | 1701 __ blx(R1); |
1685 RestoreByteCodePointer(R2); | 1702 RestoreByteCodePointer(R2); |
1686 | 1703 |
1687 __ ldr(R7, Address(R5, 1)); | 1704 __ ldr(R7, Address(R5, 1)); |
1688 // Compute the arity from the selector. | 1705 // Compute the arity from the selector. |
1689 ASSERT(Selector::ArityField::shift() == 0); | 1706 ASSERT(Selector::ArityField::shift() == 0); |
1690 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); | 1707 __ and_(R2, R7, Immediate(Selector::ArityField::mask())); |
1691 | 1708 |
1692 Drop(R2); | 1709 Drop(R2); |
1693 | 1710 |
1694 StoreLocal(R0, 0); | 1711 StoreLocal(R0, 0); |
1695 Dispatch(kInvokeMethodLength); | 1712 Dispatch(kInvokeMethodLength); |
1696 } | 1713 } |
1697 | 1714 |
1698 __ Bind(&smi); | 1715 __ Bind(&smi); |
1699 __ ldr(R2, Address(R4, Process::kProgramOffset)); | 1716 __ ldr(R2, Address(R10, Program::kSmiClassOffset)); |
1700 __ ldr(R2, Address(R2, Program::kSmiClassOffset)); | |
1701 __ b(&dispatch); | 1717 __ b(&dispatch); |
1702 | 1718 |
1703 if (test) { | 1719 if (test) { |
1704 // Invalid entry: The answer is false. | 1720 // Invalid entry: The answer is false. |
1705 __ Bind(&invalid); | 1721 __ Bind(&invalid); |
1706 StoreLocal(R11, 0); | 1722 LoadFalse(R2); |
| 1723 StoreLocal(R2, 0); |
1707 Dispatch(kInvokeTestLength); | 1724 Dispatch(kInvokeTestLength); |
1708 } else { | 1725 } else { |
1709 __ Bind(&intrinsified); | 1726 __ Bind(&intrinsified); |
1710 __ mov(PC, R2); | 1727 __ mov(PC, R2); |
1711 | 1728 |
1712 // Invalid entry: Use the noSuchMethod entry from entry zero of | 1729 // Invalid entry: Use the noSuchMethod entry from entry zero of |
1713 // the virtual table. | 1730 // the virtual table. |
1714 __ Bind(&invalid); | 1731 __ Bind(&invalid); |
1715 __ ldr(R1, Address(R4, Process::kProgramOffset)); | 1732 __ ldr(R1, Address(R10, Program::kDispatchTableOffset)); |
1716 __ ldr(R1, Address(R1, Program::kDispatchTableOffset)); | |
1717 __ ldr(R1, Address(R1, Array::kSize - HeapObject::kTag)); | 1733 __ ldr(R1, Address(R1, Array::kSize - HeapObject::kTag)); |
1718 __ b(&validated); | 1734 __ b(&validated); |
1719 } | 1735 } |
1720 } | 1736 } |
1721 | 1737 |
1722 void InterpreterGeneratorARM::InvokeNative(bool yield, bool safepoint) { | 1738 void InterpreterGeneratorARM::InvokeNative(bool yield, bool safepoint) { |
1723 __ ldrb(R1, Address(R5, 1)); | 1739 __ ldrb(R1, Address(R5, 1)); |
1724 // Also skip two empty slots. | 1740 // Also skip two empty slots. |
1725 __ adds(R1, R1, Immediate(2)); | 1741 __ adds(R1, R1, Immediate(2)); |
1726 __ ldrb(R0, Address(R5, 2)); | 1742 __ ldrb(R0, Address(R5, 2)); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1959 Condition cond) { | 1975 Condition cond) { |
1960 LoadLocal(R0, 0); | 1976 LoadLocal(R0, 0); |
1961 __ tst(R0, Immediate(Smi::kTagMask)); | 1977 __ tst(R0, Immediate(Smi::kTagMask)); |
1962 __ b(NE, fallback); | 1978 __ b(NE, fallback); |
1963 LoadLocal(R1, 1); | 1979 LoadLocal(R1, 1); |
1964 __ tst(R1, Immediate(Smi::kTagMask)); | 1980 __ tst(R1, Immediate(Smi::kTagMask)); |
1965 __ b(NE, fallback); | 1981 __ b(NE, fallback); |
1966 | 1982 |
1967 Label true_case; | 1983 Label true_case; |
1968 __ cmp(R1, R0); | 1984 __ cmp(R1, R0); |
1969 __ b(cond, &true_case); | 1985 ToBoolean(cond, R2); |
1970 | 1986 DropNAndSetTop(1, R2); |
1971 DropNAndSetTop(1, R11); | |
1972 Dispatch(5); | |
1973 | |
1974 __ Bind(&true_case); | |
1975 DropNAndSetTop(1, R10); | |
1976 Dispatch(5); | 1987 Dispatch(5); |
1977 } | 1988 } |
1978 | 1989 |
1979 void InterpreterGeneratorARM::ConditionalStore(Register reg_if_eq, | 1990 void InterpreterGeneratorARM::AddIf(Condition cond, Register reg, |
1980 Register reg_if_ne, | 1991 int add_if_eq) { |
1981 const Address& address) { | 1992 __ it(cond); |
1982 Label if_ne, done; | 1993 __ add(cond, reg, reg, Immediate(add_if_eq)); |
1983 __ b(NE, &if_ne); | 1994 } |
1984 __ str(reg_if_eq, address); | 1995 |
1985 __ b(&done); | 1996 void InterpreterGeneratorARM::LoadTrue(Register reg) { |
1986 __ Bind(&if_ne); | 1997 __ add(reg, R8, Immediate(kTrueOffset)); |
1987 __ str(reg_if_ne, address); | 1998 } |
1988 __ Bind(&done); | 1999 |
| 2000 void InterpreterGeneratorARM::LoadFalse(Register reg) { |
| 2001 __ add(reg, R8, Immediate(kFalseOffset)); |
| 2002 } |
| 2003 |
| 2004 void InterpreterGeneratorARM::ToBoolean(Condition cond, Register reg) { |
| 2005 LoadFalse(reg); |
| 2006 AddIf(cond, reg, kTrueOffset - kFalseOffset); |
1989 } | 2007 } |
1990 | 2008 |
1991 void InterpreterGeneratorARM::CheckStackOverflow(int size) { | 2009 void InterpreterGeneratorARM::CheckStackOverflow(int size) { |
1992 __ ldr(R1, Address(R4, Process::kStackLimitOffset)); | 2010 __ ldr(R1, Address(R4, Process::kStackLimitOffset)); |
1993 __ cmp(R6, R1); | 2011 __ cmp(R6, R1); |
1994 if (size == 0) { | 2012 if (size == 0) { |
1995 __ b(LS, &check_stack_overflow_0_); | 2013 __ b(LS, &check_stack_overflow_0_); |
1996 } else { | 2014 } else { |
1997 Label done; | 2015 Label done; |
1998 __ b(HI, &done); | 2016 __ b(HI, &done); |
1999 __ mov(R0, Immediate(size)); | 2017 __ mov(R0, Immediate(size)); |
2000 __ b(&check_stack_overflow_); | 2018 __ b(&check_stack_overflow_); |
2001 __ Bind(&done); | 2019 __ Bind(&done); |
2002 } | 2020 } |
2003 } | 2021 } |
2004 | 2022 |
2005 void InterpreterGeneratorARM::Dispatch(int size) { | 2023 void InterpreterGeneratorARM::Dispatch(int size) { |
2006 // Load the next bytecode through R5 and dispatch to it. | 2024 // Load the next bytecode through R5 and dispatch to it. |
2007 #ifdef DARTINO_THUMB_ONLY | 2025 #ifdef DARTINO_THUMB_ONLY |
2008 __ ldrb(R7, Address(R5, size)); | 2026 __ ldrb(R7, Address(R5, size)); |
2009 if (size > 0) { | 2027 if (size > 0) { |
2010 __ adds(R5, R5, Immediate(size)); | 2028 __ adds(R5, R5, Immediate(size)); |
2011 } | 2029 } |
2012 #else | 2030 #else |
2013 __ ldrb(R7, Address(R5, size), WRITE_BACK); | 2031 __ ldrb(R7, Address(R5, size), WRITE_BACK); |
2014 #endif | 2032 #endif |
2015 __ ldr(R9, "Interpret_DispatchTable"); | 2033 __ ldr(PC, Address(R11, Operand(R7, TIMES_WORD_SIZE))); |
2016 __ ldr(PC, Address(R9, Operand(R7, TIMES_WORD_SIZE))); | |
2017 __ GenerateConstantPool(); | 2034 __ GenerateConstantPool(); |
2018 } | 2035 } |
2019 | 2036 |
2020 void InterpreterGeneratorARM::SaveState(Label* resume) { | 2037 void InterpreterGeneratorARM::SaveState(Label* resume) { |
2021 // Save the bytecode pointer at the return-address slot. | 2038 // Save the bytecode pointer at the return-address slot. |
2022 LoadFramePointer(R3); | 2039 LoadFramePointer(R3); |
2023 __ str(R5, Address(R3, -kWordSize)); | 2040 __ str(R5, Address(R3, -kWordSize)); |
2024 | 2041 |
2025 // Push resume address. | 2042 // Push resume address. |
2026 __ ldr(R5, resume); | 2043 __ ldr(R5, resume); |
(...skipping 14 matching lines...) Expand all Loading... |
2041 void InterpreterGeneratorARM::RestoreState() { | 2058 void InterpreterGeneratorARM::RestoreState() { |
2042 // Load the current stack pointer into R6. | 2059 // Load the current stack pointer into R6. |
2043 __ ldr(R6, Address(R4, Process::kCoroutineOffset)); | 2060 __ ldr(R6, Address(R4, Process::kCoroutineOffset)); |
2044 __ ldr(R6, Address(R6, Coroutine::kStackOffset - HeapObject::kTag)); | 2061 __ ldr(R6, Address(R6, Coroutine::kStackOffset - HeapObject::kTag)); |
2045 __ ldr(R5, Address(R6, Stack::kTopOffset - HeapObject::kTag)); | 2062 __ ldr(R5, Address(R6, Stack::kTopOffset - HeapObject::kTag)); |
2046 __ adds(R6, R6, Immediate(Stack::kSize - HeapObject::kTag)); | 2063 __ adds(R6, R6, Immediate(Stack::kSize - HeapObject::kTag)); |
2047 __ add(R6, R6, Operand(R5, TIMES_2)); | 2064 __ add(R6, R6, Operand(R5, TIMES_2)); |
2048 | 2065 |
2049 // Load constants into registers. | 2066 // Load constants into registers. |
2050 __ ldr(R10, Address(R4, Process::kProgramOffset)); | 2067 __ ldr(R10, Address(R4, Process::kProgramOffset)); |
2051 __ ldr(R11, Address(R10, Program::kFalseObjectOffset)); | |
2052 __ ldr(R8, Address(R10, Program::kNullObjectOffset)); | 2068 __ ldr(R8, Address(R10, Program::kNullObjectOffset)); |
2053 __ ldr(R10, Address(R10, Program::kTrueObjectOffset)); | 2069 __ ldr(R11, "Interpret_DispatchTable"); |
2054 | 2070 |
2055 // Pop and store frame pointer. | 2071 // Pop and store frame pointer. |
2056 Pop(R5); | 2072 Pop(R5); |
2057 StoreFramePointer(R5); | 2073 StoreFramePointer(R5); |
2058 | 2074 |
2059 // Set the bytecode pointer from the stack. | 2075 // Set the bytecode pointer from the stack. |
2060 __ ldr(R5, Address(R5, -kWordSize)); | 2076 __ ldr(R5, Address(R5, -kWordSize)); |
2061 | 2077 |
2062 // Pop and branch to resume address. | 2078 // Pop and branch to resume address. |
2063 Pop(LR); | 2079 Pop(LR); |
2064 __ mov(PC, LR); | 2080 __ mov(PC, LR); |
2065 } | 2081 } |
2066 | 2082 |
2067 } // namespace dartino | 2083 } // namespace dartino |
2068 | 2084 |
2069 #endif // defined(DARTINO_TARGET_ARM) | 2085 #endif // defined(DARTINO_TARGET_ARM) |
OLD | NEW |