| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| 11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/flow_graph_compiler.h" | 13 #include "vm/flow_graph_compiler.h" |
| 14 #include "vm/heap.h" | 14 #include "vm/heap.h" |
| 15 #include "vm/instructions.h" | 15 #include "vm/instructions.h" |
| 16 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/tags.h" | 19 #include "vm/tags.h" |
| 20 | 20 |
| 21 #define __ assembler-> | 21 #define __ assembler-> |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 26 DEFINE_FLAG(bool, use_slow_path, false, | 26 DEFINE_FLAG(bool, |
| 27 "Set to true for debugging & verifying the slow paths."); | 27 use_slow_path, |
| 28 false, |
| 29 "Set to true for debugging & verifying the slow paths."); |
| 28 DECLARE_FLAG(bool, trace_optimized_ic_calls); | 30 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 29 | 31 |
| 30 // Input parameters: | 32 // Input parameters: |
| 31 // LR : return address. | 33 // LR : return address. |
| 32 // SP : address of last argument in argument array. | 34 // SP : address of last argument in argument array. |
| 33 // SP + 4*R4 - 4 : address of first argument in argument array. | 35 // SP + 4*R4 - 4 : address of first argument in argument array. |
| 34 // SP + 4*R4 : address of return value. | 36 // SP + 4*R4 : address of return value. |
| 35 // R9 : address of the runtime function to call. | 37 // R9 : address of the runtime function to call. |
| 36 // R4 : number of arguments to the call. | 38 // R4 : number of arguments to the call. |
| 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 38 const intptr_t thread_offset = NativeArguments::thread_offset(); | 40 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 39 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 41 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 40 const intptr_t argv_offset = NativeArguments::argv_offset(); | 42 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 41 const intptr_t retval_offset = NativeArguments::retval_offset(); | 43 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 42 | 44 |
| 43 __ EnterStubFrame(); | 45 __ EnterStubFrame(); |
| 44 | 46 |
| 45 // Save exit frame information to enable stack walking as we are about | 47 // Save exit frame information to enable stack walking as we are about |
| 46 // to transition to Dart VM C++ code. | 48 // to transition to Dart VM C++ code. |
| 47 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 49 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 48 | 50 |
| 49 #if defined(DEBUG) | 51 #if defined(DEBUG) |
| 50 { Label ok; | 52 { |
| 53 Label ok; |
| 51 // Check that we are always entering from Dart code. | 54 // Check that we are always entering from Dart code. |
| 52 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); | 55 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); |
| 53 __ CompareImmediate(R8, VMTag::kDartTagId); | 56 __ CompareImmediate(R8, VMTag::kDartTagId); |
| 54 __ b(&ok, EQ); | 57 __ b(&ok, EQ); |
| 55 __ Stop("Not coming from Dart code."); | 58 __ Stop("Not coming from Dart code."); |
| 56 __ Bind(&ok); | 59 __ Bind(&ok); |
| 57 } | 60 } |
| 58 #endif | 61 #endif |
| 59 | 62 |
| 60 // Mark that the thread is executing VM code. | 63 // Mark that the thread is executing VM code. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 const intptr_t argv_offset = NativeArguments::argv_offset(); | 135 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 133 const intptr_t retval_offset = NativeArguments::retval_offset(); | 136 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 134 | 137 |
| 135 __ EnterStubFrame(); | 138 __ EnterStubFrame(); |
| 136 | 139 |
| 137 // Save exit frame information to enable stack walking as we are about | 140 // Save exit frame information to enable stack walking as we are about |
| 138 // to transition to native code. | 141 // to transition to native code. |
| 139 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 142 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 140 | 143 |
| 141 #if defined(DEBUG) | 144 #if defined(DEBUG) |
| 142 { Label ok; | 145 { |
| 146 Label ok; |
| 143 // Check that we are always entering from Dart code. | 147 // Check that we are always entering from Dart code. |
| 144 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); | 148 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); |
| 145 __ CompareImmediate(R8, VMTag::kDartTagId); | 149 __ CompareImmediate(R8, VMTag::kDartTagId); |
| 146 __ b(&ok, EQ); | 150 __ b(&ok, EQ); |
| 147 __ Stop("Not coming from Dart code."); | 151 __ Stop("Not coming from Dart code."); |
| 148 __ Bind(&ok); | 152 __ Bind(&ok); |
| 149 } | 153 } |
| 150 #endif | 154 #endif |
| 151 | 155 |
| 152 // Mark that the thread is executing native code. | 156 // Mark that the thread is executing native code. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 172 ASSERT(argv_offset == 2 * kWordSize); | 176 ASSERT(argv_offset == 2 * kWordSize); |
| 173 // Set argv in NativeArguments: R2 already contains argv. | 177 // Set argv in NativeArguments: R2 already contains argv. |
| 174 | 178 |
| 175 ASSERT(retval_offset == 3 * kWordSize); | 179 ASSERT(retval_offset == 3 * kWordSize); |
| 176 // Set retval in NativeArgs. | 180 // Set retval in NativeArgs. |
| 177 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); | 181 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); |
| 178 | 182 |
| 179 // Passing the structure by value as in runtime calls would require changing | 183 // Passing the structure by value as in runtime calls would require changing |
| 180 // Dart API for native functions. | 184 // Dart API for native functions. |
| 181 // For now, space is reserved on the stack and we pass a pointer to it. | 185 // For now, space is reserved on the stack and we pass a pointer to it. |
| 182 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); | 186 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); |
| 183 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. | 187 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. |
| 184 | 188 |
| 185 __ mov(R1, Operand(R9)); // Pass the function entrypoint to call. | 189 __ mov(R1, Operand(R9)); // Pass the function entrypoint to call. |
| 186 | 190 |
| 187 // Call native function invocation wrapper or redirection via simulator. | 191 // Call native function invocation wrapper or redirection via simulator. |
| 188 __ ldr(LR, Address(THR, Thread::native_call_wrapper_entry_point_offset())); | 192 __ ldr(LR, Address(THR, Thread::native_call_wrapper_entry_point_offset())); |
| 189 __ blx(LR); | 193 __ blx(LR); |
| 190 | 194 |
| 191 // Mark that the thread is executing Dart code. | 195 // Mark that the thread is executing Dart code. |
| 192 __ LoadImmediate(R2, VMTag::kDartTagId); | 196 __ LoadImmediate(R2, VMTag::kDartTagId); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 213 const intptr_t argv_offset = NativeArguments::argv_offset(); | 217 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 214 const intptr_t retval_offset = NativeArguments::retval_offset(); | 218 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 215 | 219 |
| 216 __ EnterStubFrame(); | 220 __ EnterStubFrame(); |
| 217 | 221 |
| 218 // Save exit frame information to enable stack walking as we are about | 222 // Save exit frame information to enable stack walking as we are about |
| 219 // to transition to native code. | 223 // to transition to native code. |
| 220 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 224 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 221 | 225 |
| 222 #if defined(DEBUG) | 226 #if defined(DEBUG) |
| 223 { Label ok; | 227 { |
| 228 Label ok; |
| 224 // Check that we are always entering from Dart code. | 229 // Check that we are always entering from Dart code. |
| 225 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); | 230 __ LoadFromOffset(kWord, R8, THR, Thread::vm_tag_offset()); |
| 226 __ CompareImmediate(R8, VMTag::kDartTagId); | 231 __ CompareImmediate(R8, VMTag::kDartTagId); |
| 227 __ b(&ok, EQ); | 232 __ b(&ok, EQ); |
| 228 __ Stop("Not coming from Dart code."); | 233 __ Stop("Not coming from Dart code."); |
| 229 __ Bind(&ok); | 234 __ Bind(&ok); |
| 230 } | 235 } |
| 231 #endif | 236 #endif |
| 232 | 237 |
| 233 // Mark that the thread is executing native code. | 238 // Mark that the thread is executing native code. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 253 ASSERT(argv_offset == 2 * kWordSize); | 258 ASSERT(argv_offset == 2 * kWordSize); |
| 254 // Set argv in NativeArguments: R2 already contains argv. | 259 // Set argv in NativeArguments: R2 already contains argv. |
| 255 | 260 |
| 256 ASSERT(retval_offset == 3 * kWordSize); | 261 ASSERT(retval_offset == 3 * kWordSize); |
| 257 // Set retval in NativeArgs. | 262 // Set retval in NativeArgs. |
| 258 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); | 263 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); |
| 259 | 264 |
| 260 // Passing the structure by value as in runtime calls would require changing | 265 // Passing the structure by value as in runtime calls would require changing |
| 261 // Dart API for native functions. | 266 // Dart API for native functions. |
| 262 // For now, space is reserved on the stack and we pass a pointer to it. | 267 // For now, space is reserved on the stack and we pass a pointer to it. |
| 263 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); | 268 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); |
| 264 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. | 269 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. |
| 265 | 270 |
| 266 // Call native function or redirection via simulator. | 271 // Call native function or redirection via simulator. |
| 267 __ blx(R9); | 272 __ blx(R9); |
| 268 | 273 |
| 269 // Mark that the thread is executing Dart code. | 274 // Mark that the thread is executing Dart code. |
| 270 __ LoadImmediate(R2, VMTag::kDartTagId); | 275 __ LoadImmediate(R2, VMTag::kDartTagId); |
| 271 __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset()); | 276 __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset()); |
| 272 | 277 |
| 273 // Reset exit frame information in Isolate structure. | 278 // Reset exit frame information in Isolate structure. |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 __ vstmd(DB_W, SP, D16, kNumberOfDRegisters - 16); | 461 __ vstmd(DB_W, SP, D16, kNumberOfDRegisters - 16); |
| 457 __ vstmd(DB_W, SP, D0, 16); | 462 __ vstmd(DB_W, SP, D0, 16); |
| 458 } else { | 463 } else { |
| 459 __ vstmd(DB_W, SP, D0, kNumberOfDRegisters); | 464 __ vstmd(DB_W, SP, D0, kNumberOfDRegisters); |
| 460 } | 465 } |
| 461 } else { | 466 } else { |
| 462 __ AddImmediate(SP, SP, -kNumberOfFpuRegisters * kFpuRegisterSize); | 467 __ AddImmediate(SP, SP, -kNumberOfFpuRegisters * kFpuRegisterSize); |
| 463 } | 468 } |
| 464 | 469 |
| 465 __ mov(R0, Operand(SP)); // Pass address of saved registers block. | 470 __ mov(R0, Operand(SP)); // Pass address of saved registers block. |
| 466 bool is_lazy = (kind == kLazyDeoptFromReturn) || | 471 bool is_lazy = |
| 467 (kind == kLazyDeoptFromThrow); | 472 (kind == kLazyDeoptFromReturn) || (kind == kLazyDeoptFromThrow); |
| 468 __ mov(R1, Operand(is_lazy ? 1 : 0)); | 473 __ mov(R1, Operand(is_lazy ? 1 : 0)); |
| 469 __ ReserveAlignedFrameSpace(0); | 474 __ ReserveAlignedFrameSpace(0); |
| 470 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); | 475 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); |
| 471 // Result (R0) is stack-size (FP - SP) in bytes. | 476 // Result (R0) is stack-size (FP - SP) in bytes. |
| 472 | 477 |
| 473 if (kind == kLazyDeoptFromReturn) { | 478 if (kind == kLazyDeoptFromReturn) { |
| 474 // Restore result into R1 temporarily. | 479 // Restore result into R1 temporarily. |
| 475 __ ldr(R1, Address(FP, saved_result_slot_from_fp * kWordSize)); | 480 __ ldr(R1, Address(FP, saved_result_slot_from_fp * kWordSize)); |
| 476 } else if (kind == kLazyDeoptFromThrow) { | 481 } else if (kind == kLazyDeoptFromThrow) { |
| 477 // Restore result into R1 temporarily. | 482 // Restore result into R1 temporarily. |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 // Input parameters: | 643 // Input parameters: |
| 639 // LR: return address. | 644 // LR: return address. |
| 640 // R1: array element type (either NULL or an instantiated type). | 645 // R1: array element type (either NULL or an instantiated type). |
| 641 // R2: array length as Smi (must be preserved). | 646 // R2: array length as Smi (must be preserved). |
| 642 // The newly allocated object is returned in R0. | 647 // The newly allocated object is returned in R0. |
| 643 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 648 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 644 Label slow_case; | 649 Label slow_case; |
| 645 // Compute the size to be allocated, it is based on the array length | 650 // Compute the size to be allocated, it is based on the array length |
| 646 // and is computed as: | 651 // and is computed as: |
| 647 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 652 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 648 __ MoveRegister(R3, R2); // Array length. | 653 __ MoveRegister(R3, R2); // Array length. |
| 649 // Check that length is a positive Smi. | 654 // Check that length is a positive Smi. |
| 650 __ tst(R3, Operand(kSmiTagMask)); | 655 __ tst(R3, Operand(kSmiTagMask)); |
| 651 if (FLAG_use_slow_path) { | 656 if (FLAG_use_slow_path) { |
| 652 __ b(&slow_case); | 657 __ b(&slow_case); |
| 653 } else { | 658 } else { |
| 654 __ b(&slow_case, NE); | 659 __ b(&slow_case, NE); |
| 655 } | 660 } |
| 656 __ cmp(R3, Operand(0)); | 661 __ cmp(R3, Operand(0)); |
| 657 __ b(&slow_case, LT); | 662 __ b(&slow_case, LT); |
| 658 | 663 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 670 __ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi. | 675 __ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi. |
| 671 ASSERT(kSmiTagShift == 1); | 676 ASSERT(kSmiTagShift == 1); |
| 672 __ bic(R9, R9, Operand(kObjectAlignment - 1)); | 677 __ bic(R9, R9, Operand(kObjectAlignment - 1)); |
| 673 | 678 |
| 674 // R9: Allocation size. | 679 // R9: Allocation size. |
| 675 Heap::Space space = Heap::kNew; | 680 Heap::Space space = Heap::kNew; |
| 676 __ ldr(R8, Address(THR, Thread::heap_offset())); | 681 __ ldr(R8, Address(THR, Thread::heap_offset())); |
| 677 // Potential new object start. | 682 // Potential new object start. |
| 678 __ ldr(R0, Address(R8, Heap::TopOffset(space))); | 683 __ ldr(R0, Address(R8, Heap::TopOffset(space))); |
| 679 __ adds(NOTFP, R0, Operand(R9)); // Potential next object start. | 684 __ adds(NOTFP, R0, Operand(R9)); // Potential next object start. |
| 680 __ b(&slow_case, CS); // Branch if unsigned overflow. | 685 __ b(&slow_case, CS); // Branch if unsigned overflow. |
| 681 | 686 |
| 682 // Check if the allocation fits into the remaining space. | 687 // Check if the allocation fits into the remaining space. |
| 683 // R0: potential new object start. | 688 // R0: potential new object start. |
| 684 // NOTFP: potential next object start. | 689 // NOTFP: potential next object start. |
| 685 // R9: allocation size. | 690 // R9: allocation size. |
| 686 __ ldr(R3, Address(R8, Heap::EndOffset(space))); | 691 __ ldr(R3, Address(R8, Heap::EndOffset(space))); |
| 687 __ cmp(NOTFP, Operand(R3)); | 692 __ cmp(NOTFP, Operand(R3)); |
| 688 __ b(&slow_case, CS); | 693 __ b(&slow_case, CS); |
| 689 | 694 |
| 690 // Successfully allocated the object(s), now update top to point to | 695 // Successfully allocated the object(s), now update top to point to |
| (...skipping 17 matching lines...) Expand all Loading... |
| 708 // Get the class index and insert it into the tags. | 713 // Get the class index and insert it into the tags. |
| 709 // R8: size and bit tags. | 714 // R8: size and bit tags. |
| 710 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); | 715 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); |
| 711 __ orr(R8, R8, Operand(TMP)); | 716 __ orr(R8, R8, Operand(TMP)); |
| 712 __ str(R8, FieldAddress(R0, Array::tags_offset())); // Store tags. | 717 __ str(R8, FieldAddress(R0, Array::tags_offset())); // Store tags. |
| 713 } | 718 } |
| 714 | 719 |
| 715 // R0: new object start as a tagged pointer. | 720 // R0: new object start as a tagged pointer. |
| 716 // NOTFP: new object end address. | 721 // NOTFP: new object end address. |
| 717 // Store the type argument field. | 722 // Store the type argument field. |
| 718 __ StoreIntoObjectNoBarrier(R0, | 723 __ StoreIntoObjectNoBarrier( |
| 719 FieldAddress(R0, Array::type_arguments_offset()), | 724 R0, FieldAddress(R0, Array::type_arguments_offset()), R1); |
| 720 R1); | |
| 721 | 725 |
| 722 // Set the length field. | 726 // Set the length field. |
| 723 __ StoreIntoObjectNoBarrier(R0, | 727 __ StoreIntoObjectNoBarrier(R0, FieldAddress(R0, Array::length_offset()), R2); |
| 724 FieldAddress(R0, Array::length_offset()), | |
| 725 R2); | |
| 726 | 728 |
| 727 // Initialize all array elements to raw_null. | 729 // Initialize all array elements to raw_null. |
| 728 // R0: new object start as a tagged pointer. | 730 // R0: new object start as a tagged pointer. |
| 729 // R3: allocation stats address. | 731 // R3: allocation stats address. |
| 730 // R8, R9: null | 732 // R8, R9: null |
| 731 // R4: iterator which initially points to the start of the variable | 733 // R4: iterator which initially points to the start of the variable |
| 732 // data area to be initialized. | 734 // data area to be initialized. |
| 733 // NOTFP: new object end address. | 735 // NOTFP: new object end address. |
| 734 // R9: allocation size. | 736 // R9: allocation size. |
| 735 NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R3, R9, space)); | 737 NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R3, R9, space)); |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1014 // R0: Address being stored | 1016 // R0: Address being stored |
| 1015 __ ldr(R2, FieldAddress(R0, Object::tags_offset())); | 1017 __ ldr(R2, FieldAddress(R0, Object::tags_offset())); |
| 1016 __ tst(R2, Operand(1 << RawObject::kRememberedBit)); | 1018 __ tst(R2, Operand(1 << RawObject::kRememberedBit)); |
| 1017 __ b(&add_to_buffer, EQ); | 1019 __ b(&add_to_buffer, EQ); |
| 1018 __ PopList((1 << R1) | (1 << R2) | (1 << R3)); | 1020 __ PopList((1 << R1) | (1 << R2) | (1 << R3)); |
| 1019 __ Ret(); | 1021 __ Ret(); |
| 1020 | 1022 |
| 1021 __ Bind(&add_to_buffer); | 1023 __ Bind(&add_to_buffer); |
| 1022 // R2: Header word. | 1024 // R2: Header word. |
| 1023 if (TargetCPUFeatures::arm_version() == ARMv5TE) { | 1025 if (TargetCPUFeatures::arm_version() == ARMv5TE) { |
| 1024 // TODO(21263): Implement 'swp' and use it below. | 1026 // TODO(21263): Implement 'swp' and use it below. |
| 1025 #if !defined(USING_SIMULATOR) | 1027 #if !defined(USING_SIMULATOR) |
| 1026 ASSERT(OS::NumberOfAvailableProcessors() <= 1); | 1028 ASSERT(OS::NumberOfAvailableProcessors() <= 1); |
| 1027 #endif | 1029 #endif |
| 1028 __ orr(R2, R2, Operand(1 << RawObject::kRememberedBit)); | 1030 __ orr(R2, R2, Operand(1 << RawObject::kRememberedBit)); |
| 1029 __ str(R2, FieldAddress(R0, Object::tags_offset())); | 1031 __ str(R2, FieldAddress(R0, Object::tags_offset())); |
| 1030 } else { | 1032 } else { |
| 1031 // Atomically set the remembered bit of the object header. | 1033 // Atomically set the remembered bit of the object header. |
| 1032 ASSERT(Object::tags_offset() == 0); | 1034 ASSERT(Object::tags_offset() == 0); |
| 1033 __ sub(R3, R0, Operand(kHeapObjectTag)); | 1035 __ sub(R3, R0, Operand(kHeapObjectTag)); |
| 1034 // R3: Untagged address of header word (ldrex/strex do not support offsets). | 1036 // R3: Untagged address of header word (ldrex/strex do not support offsets). |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 // R9: allocation stats table. | 1142 // R9: allocation stats table. |
| 1141 // First try inlining the initialization without a loop. | 1143 // First try inlining the initialization without a loop. |
| 1142 if (instance_size < (kInlineInstanceSize * kWordSize)) { | 1144 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
| 1143 // Small objects are initialized using a consecutive set of writes. | 1145 // Small objects are initialized using a consecutive set of writes. |
| 1144 intptr_t begin_offset = Instance::NextFieldOffset() - kHeapObjectTag; | 1146 intptr_t begin_offset = Instance::NextFieldOffset() - kHeapObjectTag; |
| 1145 intptr_t end_offset = instance_size - kHeapObjectTag; | 1147 intptr_t end_offset = instance_size - kHeapObjectTag; |
| 1146 // Save one move if less than two fields. | 1148 // Save one move if less than two fields. |
| 1147 if ((end_offset - begin_offset) >= (2 * kWordSize)) { | 1149 if ((end_offset - begin_offset) >= (2 * kWordSize)) { |
| 1148 __ mov(R3, Operand(R2)); | 1150 __ mov(R3, Operand(R2)); |
| 1149 } | 1151 } |
| 1150 __ InitializeFieldsNoBarrierUnrolled(R0, R0, begin_offset, end_offset, | 1152 __ InitializeFieldsNoBarrierUnrolled(R0, R0, begin_offset, end_offset, R2, |
| 1151 R2, R3); | 1153 R3); |
| 1152 } else { | 1154 } else { |
| 1153 // There are more than kInlineInstanceSize(12) fields | 1155 // There are more than kInlineInstanceSize(12) fields |
| 1154 __ add(R4, R0, Operand(Instance::NextFieldOffset() - kHeapObjectTag)); | 1156 __ add(R4, R0, Operand(Instance::NextFieldOffset() - kHeapObjectTag)); |
| 1155 __ mov(R3, Operand(R2)); | 1157 __ mov(R3, Operand(R2)); |
| 1156 // Loop until the whole object is initialized. | 1158 // Loop until the whole object is initialized. |
| 1157 // R2: raw null. | 1159 // R2: raw null. |
| 1158 // R3: raw null. | 1160 // R3: raw null. |
| 1159 // R0: new object (tagged). | 1161 // R0: new object (tagged). |
| 1160 // R1: next object start. | 1162 // R1: next object start. |
| 1161 // R4: next word to be initialized. | 1163 // R4: next word to be initialized. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1184 if (is_cls_parameterized) { | 1186 if (is_cls_parameterized) { |
| 1185 // Load the type arguments. | 1187 // Load the type arguments. |
| 1186 __ ldr(R4, Address(SP, 0)); | 1188 __ ldr(R4, Address(SP, 0)); |
| 1187 } | 1189 } |
| 1188 // If is_cls_parameterized: | 1190 // If is_cls_parameterized: |
| 1189 // R4: new object type arguments. | 1191 // R4: new object type arguments. |
| 1190 // Create a stub frame as we are pushing some objects on the stack before | 1192 // Create a stub frame as we are pushing some objects on the stack before |
| 1191 // calling into the runtime. | 1193 // calling into the runtime. |
| 1192 __ EnterStubFrame(); // Uses pool pointer to pass cls to runtime. | 1194 __ EnterStubFrame(); // Uses pool pointer to pass cls to runtime. |
| 1193 __ LoadObject(R2, Object::null_object()); | 1195 __ LoadObject(R2, Object::null_object()); |
| 1194 __ Push(R2); // Setup space on stack for return value. | 1196 __ Push(R2); // Setup space on stack for return value. |
| 1195 __ PushObject(cls); // Push class of object to be allocated. | 1197 __ PushObject(cls); // Push class of object to be allocated. |
| 1196 if (is_cls_parameterized) { | 1198 if (is_cls_parameterized) { |
| 1197 // Push type arguments. | 1199 // Push type arguments. |
| 1198 __ Push(R4); | 1200 __ Push(R4); |
| 1199 } else { | 1201 } else { |
| 1200 // Push null type arguments. | 1202 // Push null type arguments. |
| 1201 __ Push(R2); | 1203 __ Push(R2); |
| 1202 } | 1204 } |
| 1203 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1205 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 1204 __ Drop(2); // Pop arguments. | 1206 __ Drop(2); // Pop arguments. |
| 1205 __ Pop(R0); // Pop result (newly allocated object). | 1207 __ Pop(R0); // Pop result (newly allocated object). |
| 1206 // R0: new object | 1208 // R0: new object |
| 1207 // Restore the frame pointer. | 1209 // Restore the frame pointer. |
| 1208 __ LeaveStubFrame(); | 1210 __ LeaveStubFrame(); |
| 1209 __ Ret(); | 1211 __ Ret(); |
| 1210 } | 1212 } |
| 1211 | 1213 |
| 1212 | 1214 |
| 1213 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function | 1215 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function |
| 1214 // from the entry code of a dart function after an error in passed argument | 1216 // from the entry code of a dart function after an error in passed argument |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1244 // R8: function object. | 1246 // R8: function object. |
| 1245 // R9: inline cache data object. | 1247 // R9: inline cache data object. |
| 1246 // Cannot use function object from ICData as it may be the inlined | 1248 // Cannot use function object from ICData as it may be the inlined |
| 1247 // function and not the top-scope function. | 1249 // function and not the top-scope function. |
| 1248 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 1250 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1249 Register ic_reg = R9; | 1251 Register ic_reg = R9; |
| 1250 Register func_reg = R8; | 1252 Register func_reg = R8; |
| 1251 if (FLAG_trace_optimized_ic_calls) { | 1253 if (FLAG_trace_optimized_ic_calls) { |
| 1252 __ EnterStubFrame(); | 1254 __ EnterStubFrame(); |
| 1253 __ PushList((1 << R9) | (1 << R8)); // Preserve. | 1255 __ PushList((1 << R9) | (1 << R8)); // Preserve. |
| 1254 __ Push(ic_reg); // Argument. | 1256 __ Push(ic_reg); // Argument. |
| 1255 __ Push(func_reg); // Argument. | 1257 __ Push(func_reg); // Argument. |
| 1256 __ CallRuntime(kTraceICCallRuntimeEntry, 2); | 1258 __ CallRuntime(kTraceICCallRuntimeEntry, 2); |
| 1257 __ Drop(2); // Discard argument; | 1259 __ Drop(2); // Discard argument; |
| 1258 __ PopList((1 << R9) | (1 << R8)); // Restore. | 1260 __ PopList((1 << R9) | (1 << R8)); // Restore. |
| 1259 __ LeaveStubFrame(); | 1261 __ LeaveStubFrame(); |
| 1260 } | 1262 } |
| 1261 __ ldr(NOTFP, FieldAddress(func_reg, Function::usage_counter_offset())); | 1263 __ ldr(NOTFP, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1262 __ add(NOTFP, NOTFP, Operand(1)); | 1264 __ add(NOTFP, NOTFP, Operand(1)); |
| 1263 __ str(NOTFP, FieldAddress(func_reg, Function::usage_counter_offset())); | 1265 __ str(NOTFP, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1264 } | 1266 } |
| 1265 | 1267 |
| 1266 | 1268 |
| 1267 // Loads function into 'temp_reg'. | 1269 // Loads function into 'temp_reg'. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1289 intptr_t num_args, | 1291 intptr_t num_args, |
| 1290 Label* not_smi_or_overflow) { | 1292 Label* not_smi_or_overflow) { |
| 1291 __ Comment("Fast Smi op"); | 1293 __ Comment("Fast Smi op"); |
| 1292 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1294 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1293 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1295 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1294 __ orr(TMP, R0, Operand(R1)); | 1296 __ orr(TMP, R0, Operand(R1)); |
| 1295 __ tst(TMP, Operand(kSmiTagMask)); | 1297 __ tst(TMP, Operand(kSmiTagMask)); |
| 1296 __ b(not_smi_or_overflow, NE); | 1298 __ b(not_smi_or_overflow, NE); |
| 1297 switch (kind) { | 1299 switch (kind) { |
| 1298 case Token::kADD: { | 1300 case Token::kADD: { |
| 1299 __ adds(R0, R1, Operand(R0)); // Adds. | 1301 __ adds(R0, R1, Operand(R0)); // Adds. |
| 1300 __ b(not_smi_or_overflow, VS); // Branch if overflow. | 1302 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1301 break; | 1303 break; |
| 1302 } | 1304 } |
| 1303 case Token::kSUB: { | 1305 case Token::kSUB: { |
| 1304 __ subs(R0, R1, Operand(R0)); // Subtract. | 1306 __ subs(R0, R1, Operand(R0)); // Subtract. |
| 1305 __ b(not_smi_or_overflow, VS); // Branch if overflow. | 1307 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1306 break; | 1308 break; |
| 1307 } | 1309 } |
| 1308 case Token::kEQ: { | 1310 case Token::kEQ: { |
| 1309 __ cmp(R0, Operand(R1)); | 1311 __ cmp(R0, Operand(R1)); |
| 1310 __ LoadObject(R0, Bool::True(), EQ); | 1312 __ LoadObject(R0, Bool::True(), EQ); |
| 1311 __ LoadObject(R0, Bool::False(), NE); | 1313 __ LoadObject(R0, Bool::False(), NE); |
| 1312 break; | 1314 break; |
| 1313 } | 1315 } |
| 1314 default: UNIMPLEMENTED(); | 1316 default: |
| 1317 UNIMPLEMENTED(); |
| 1315 } | 1318 } |
| 1316 // R9: IC data object (preserved). | 1319 // R9: IC data object (preserved). |
| 1317 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); | 1320 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); |
| 1318 // R8: ic_data_array with check entries: classes and target functions. | 1321 // R8: ic_data_array with check entries: classes and target functions. |
| 1319 __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag); | 1322 __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag); |
| 1320 // R8: points directly to the first ic data array element. | 1323 // R8: points directly to the first ic data array element. |
| 1321 #if defined(DEBUG) | 1324 #if defined(DEBUG) |
| 1322 // Check that first entry is for Smi/Smi. | 1325 // Check that first entry is for Smi/Smi. |
| 1323 Label error, ok; | 1326 Label error, ok; |
| 1324 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); | 1327 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); |
| 1325 __ ldr(R1, Address(R8, 0)); | 1328 __ ldr(R1, Address(R8, 0)); |
| 1326 __ CompareImmediate(R1, imm_smi_cid); | 1329 __ CompareImmediate(R1, imm_smi_cid); |
| 1327 __ b(&error, NE); | 1330 __ b(&error, NE); |
| 1328 __ ldr(R1, Address(R8, kWordSize)); | 1331 __ ldr(R1, Address(R8, kWordSize)); |
| 1329 __ CompareImmediate(R1, imm_smi_cid); | 1332 __ CompareImmediate(R1, imm_smi_cid); |
| 1330 __ b(&ok, EQ); | 1333 __ b(&ok, EQ); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1356 // - Match not found -> jump to IC miss. | 1359 // - Match not found -> jump to IC miss. |
| 1357 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1360 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1358 Assembler* assembler, | 1361 Assembler* assembler, |
| 1359 intptr_t num_args, | 1362 intptr_t num_args, |
| 1360 const RuntimeEntry& handle_ic_miss, | 1363 const RuntimeEntry& handle_ic_miss, |
| 1361 Token::Kind kind, | 1364 Token::Kind kind, |
| 1362 bool optimized) { | 1365 bool optimized) { |
| 1363 __ CheckCodePointer(); | 1366 __ CheckCodePointer(); |
| 1364 ASSERT(num_args > 0); | 1367 ASSERT(num_args > 0); |
| 1365 #if defined(DEBUG) | 1368 #if defined(DEBUG) |
| 1366 { Label ok; | 1369 { |
| 1370 Label ok; |
| 1367 // Check that the IC data array has NumArgsTested() == num_args. | 1371 // Check that the IC data array has NumArgsTested() == num_args. |
| 1368 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1372 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1369 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); | 1373 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); |
| 1370 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1374 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1371 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); | 1375 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); |
| 1372 __ CompareImmediate(R8, num_args); | 1376 __ CompareImmediate(R8, num_args); |
| 1373 __ b(&ok, EQ); | 1377 __ b(&ok, EQ); |
| 1374 __ Stop("Incorrect stub for IC data"); | 1378 __ Stop("Incorrect stub for IC data"); |
| 1375 __ Bind(&ok); | 1379 __ Bind(&ok); |
| 1376 } | 1380 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1436 } | 1440 } |
| 1437 __ Bind(&update); | 1441 __ Bind(&update); |
| 1438 // Reload receiver class ID. It has not been destroyed when num_args == 1. | 1442 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1439 if (num_args > 1) { | 1443 if (num_args > 1) { |
| 1440 __ ldr(R0, Address(SP, NOTFP, LSL, 1)); | 1444 __ ldr(R0, Address(SP, NOTFP, LSL, 1)); |
| 1441 __ LoadTaggedClassIdMayBeSmi(R0, R0); | 1445 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1442 } | 1446 } |
| 1443 | 1447 |
| 1444 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; | 1448 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1445 __ AddImmediate(R8, entry_size); // Next entry. | 1449 __ AddImmediate(R8, entry_size); // Next entry. |
| 1446 __ ldr(R1, Address(R8, 0)); // Next class ID. | 1450 __ ldr(R1, Address(R8, 0)); // Next class ID. |
| 1447 | 1451 |
| 1448 __ Bind(&test); | 1452 __ Bind(&test); |
| 1449 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? | 1453 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? |
| 1450 __ b(&loop, NE); | 1454 __ b(&loop, NE); |
| 1451 | 1455 |
| 1452 __ Comment("IC miss"); | 1456 __ Comment("IC miss"); |
| 1453 // Compute address of arguments. | 1457 // Compute address of arguments. |
| 1454 // NOTFP: argument_count - 1 (smi). | 1458 // NOTFP: argument_count - 1 (smi). |
| 1455 __ add(NOTFP, SP, Operand(NOTFP, LSL, 1)); // NOTFP is Smi. | 1459 __ add(NOTFP, SP, Operand(NOTFP, LSL, 1)); // NOTFP is Smi. |
| 1456 // NOTFP: address of receiver. | 1460 // NOTFP: address of receiver. |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1522 // LR: return address. | 1526 // LR: return address. |
| 1523 // R9: inline cache data object. | 1527 // R9: inline cache data object. |
| 1524 // Inline cache data object structure: | 1528 // Inline cache data object structure: |
| 1525 // 0: function-name | 1529 // 0: function-name |
| 1526 // 1: N, number of arguments checked. | 1530 // 1: N, number of arguments checked. |
| 1527 // 2 .. (length - 1): group of checks, each check containing: | 1531 // 2 .. (length - 1): group of checks, each check containing: |
| 1528 // - N classes. | 1532 // - N classes. |
| 1529 // - 1 target function. | 1533 // - 1 target function. |
| 1530 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1534 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1531 GenerateUsageCounterIncrement(assembler, R8); | 1535 GenerateUsageCounterIncrement(assembler, R8); |
| 1532 GenerateNArgsCheckInlineCacheStub(assembler, | 1536 GenerateNArgsCheckInlineCacheStub( |
| 1533 1, | 1537 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1534 kInlineCacheMissHandlerOneArgRuntimeEntry, | |
| 1535 Token::kILLEGAL); | |
| 1536 } | 1538 } |
| 1537 | 1539 |
| 1538 | 1540 |
| 1539 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1541 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1540 GenerateUsageCounterIncrement(assembler, R8); | 1542 GenerateUsageCounterIncrement(assembler, R8); |
| 1541 GenerateNArgsCheckInlineCacheStub(assembler, | 1543 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1542 2, | 1544 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1543 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1545 Token::kILLEGAL); |
| 1544 Token::kILLEGAL); | |
| 1545 } | 1546 } |
| 1546 | 1547 |
| 1547 | 1548 |
| 1548 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | 1549 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1549 GenerateUsageCounterIncrement(assembler, R8); | 1550 GenerateUsageCounterIncrement(assembler, R8); |
| 1550 GenerateNArgsCheckInlineCacheStub(assembler, | 1551 GenerateNArgsCheckInlineCacheStub( |
| 1551 2, | 1552 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); |
| 1552 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | |
| 1553 Token::kADD); | |
| 1554 } | 1553 } |
| 1555 | 1554 |
| 1556 | 1555 |
| 1557 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | 1556 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1558 GenerateUsageCounterIncrement(assembler, R8); | 1557 GenerateUsageCounterIncrement(assembler, R8); |
| 1559 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1558 GenerateNArgsCheckInlineCacheStub( |
| 1560 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); | 1559 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1561 } | 1560 } |
| 1562 | 1561 |
| 1563 | 1562 |
| 1564 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | 1563 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1565 GenerateUsageCounterIncrement(assembler, R8); | 1564 GenerateUsageCounterIncrement(assembler, R8); |
| 1566 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1565 GenerateNArgsCheckInlineCacheStub( |
| 1567 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); | 1566 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1568 } | 1567 } |
| 1569 | 1568 |
| 1570 | 1569 |
| 1571 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1570 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1572 Assembler* assembler) { | 1571 Assembler* assembler) { |
| 1573 GenerateOptimizedUsageCounterIncrement(assembler); | 1572 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1574 GenerateNArgsCheckInlineCacheStub(assembler, 1, | 1573 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1575 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1574 kInlineCacheMissHandlerOneArgRuntimeEntry, |
| 1576 true /* optimized */); | 1575 Token::kILLEGAL, true /* optimized */); |
| 1577 } | 1576 } |
| 1578 | 1577 |
| 1579 | 1578 |
| 1580 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1579 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1581 Assembler* assembler) { | 1580 Assembler* assembler) { |
| 1582 GenerateOptimizedUsageCounterIncrement(assembler); | 1581 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1583 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1582 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1584 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL, | 1583 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1585 true /* optimized */); | 1584 Token::kILLEGAL, true /* optimized */); |
| 1586 } | 1585 } |
| 1587 | 1586 |
| 1588 | 1587 |
| 1589 // Intermediary stub between a static call and its target. ICData contains | 1588 // Intermediary stub between a static call and its target. ICData contains |
| 1590 // the target function and the call count. | 1589 // the target function and the call count. |
| 1591 // R9: ICData | 1590 // R9: ICData |
| 1592 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1591 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1593 GenerateUsageCounterIncrement(assembler, R8); | 1592 GenerateUsageCounterIncrement(assembler, R8); |
| 1594 #if defined(DEBUG) | 1593 #if defined(DEBUG) |
| 1595 { Label ok; | 1594 { |
| 1595 Label ok; |
| 1596 // Check that the IC data array has NumArgsTested() == 0. | 1596 // Check that the IC data array has NumArgsTested() == 0. |
| 1597 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1597 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1598 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); | 1598 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); |
| 1599 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1599 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1600 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); | 1600 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); |
| 1601 __ CompareImmediate(R8, 0); | 1601 __ CompareImmediate(R8, 0); |
| 1602 __ b(&ok, EQ); | 1602 __ b(&ok, EQ); |
| 1603 __ Stop("Incorrect IC data for unoptimized static call"); | 1603 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1604 __ Bind(&ok); | 1604 __ Bind(&ok); |
| 1605 } | 1605 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 | 1655 |
| 1656 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1656 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1657 GenerateUsageCounterIncrement(assembler, R8); | 1657 GenerateUsageCounterIncrement(assembler, R8); |
| 1658 GenerateNArgsCheckInlineCacheStub( | 1658 GenerateNArgsCheckInlineCacheStub( |
| 1659 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); | 1659 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1660 } | 1660 } |
| 1661 | 1661 |
| 1662 | 1662 |
| 1663 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1663 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1664 GenerateUsageCounterIncrement(assembler, R8); | 1664 GenerateUsageCounterIncrement(assembler, R8); |
| 1665 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1665 GenerateNArgsCheckInlineCacheStub( |
| 1666 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); | 1666 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1667 } | 1667 } |
| 1668 | 1668 |
| 1669 | 1669 |
| 1670 // Stub for compiling a function and jumping to the compiled code. | 1670 // Stub for compiling a function and jumping to the compiled code. |
| 1671 // R9: IC-Data (for methods). | 1671 // R9: IC-Data (for methods). |
| 1672 // R4: Arguments descriptor. | 1672 // R4: Arguments descriptor. |
| 1673 // R0: Function. | 1673 // R0: Function. |
| 1674 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1674 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1675 // Preserve arg desc. and IC data object. | 1675 // Preserve arg desc. and IC data object. |
| 1676 __ EnterStubFrame(); | 1676 __ EnterStubFrame(); |
| 1677 __ PushList((1 << R4) | (1 << R9)); | 1677 __ PushList((1 << R4) | (1 << R9)); |
| 1678 __ Push(R0); // Pass function. | 1678 __ Push(R0); // Pass function. |
| 1679 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1679 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1680 __ Pop(R0); // Restore argument. | 1680 __ Pop(R0); // Restore argument. |
| 1681 __ PopList((1 << R4) | (1 << R9)); // Restore arg desc. and IC data. | 1681 __ PopList((1 << R4) | (1 << R9)); // Restore arg desc. and IC data. |
| 1682 __ LeaveStubFrame(); | 1682 __ LeaveStubFrame(); |
| 1683 | 1683 |
| 1684 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | 1684 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1685 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1685 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 1686 __ bx(R2); | 1686 __ bx(R2); |
| 1687 } | 1687 } |
| 1688 | 1688 |
| 1689 | 1689 |
| 1690 // R9: Contains an ICData. | 1690 // R9: Contains an ICData. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1709 __ PushList((1 << R0)); | 1709 __ PushList((1 << R0)); |
| 1710 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1710 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1711 __ PopList((1 << CODE_REG)); | 1711 __ PopList((1 << CODE_REG)); |
| 1712 __ LeaveStubFrame(); | 1712 __ LeaveStubFrame(); |
| 1713 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); | 1713 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 1714 __ bx(R0); | 1714 __ bx(R0); |
| 1715 } | 1715 } |
| 1716 | 1716 |
| 1717 | 1717 |
| 1718 // Called only from unoptimized code. All relevant registers have been saved. | 1718 // Called only from unoptimized code. All relevant registers have been saved. |
| 1719 void StubCode::GenerateDebugStepCheckStub( | 1719 void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) { |
| 1720 Assembler* assembler) { | |
| 1721 // Check single stepping. | 1720 // Check single stepping. |
| 1722 Label stepping, done_stepping; | 1721 Label stepping, done_stepping; |
| 1723 __ LoadIsolate(R1); | 1722 __ LoadIsolate(R1); |
| 1724 __ ldrb(R1, Address(R1, Isolate::single_step_offset())); | 1723 __ ldrb(R1, Address(R1, Isolate::single_step_offset())); |
| 1725 __ CompareImmediate(R1, 0); | 1724 __ CompareImmediate(R1, 0); |
| 1726 __ b(&stepping, NE); | 1725 __ b(&stepping, NE); |
| 1727 __ Bind(&done_stepping); | 1726 __ Bind(&done_stepping); |
| 1728 __ Ret(); | 1727 __ Ret(); |
| 1729 | 1728 |
| 1730 __ Bind(&stepping); | 1729 __ Bind(&stepping); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1742 // R2: cache array. | 1741 // R2: cache array. |
| 1743 // Result in R1: null -> not found, otherwise result (true or false). | 1742 // Result in R1: null -> not found, otherwise result (true or false). |
| 1744 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) { | 1743 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) { |
| 1745 ASSERT((1 <= n) && (n <= 3)); | 1744 ASSERT((1 <= n) && (n <= 3)); |
| 1746 if (n > 1) { | 1745 if (n > 1) { |
| 1747 // Get instance type arguments. | 1746 // Get instance type arguments. |
| 1748 __ LoadClass(R3, R0, R4); | 1747 __ LoadClass(R3, R0, R4); |
| 1749 // Compute instance type arguments into R4. | 1748 // Compute instance type arguments into R4. |
| 1750 Label has_no_type_arguments; | 1749 Label has_no_type_arguments; |
| 1751 __ LoadObject(R4, Object::null_object()); | 1750 __ LoadObject(R4, Object::null_object()); |
| 1752 __ ldr(R9, FieldAddress(R3, | 1751 __ ldr(R9, FieldAddress( |
| 1753 Class::type_arguments_field_offset_in_words_offset())); | 1752 R3, Class::type_arguments_field_offset_in_words_offset())); |
| 1754 __ CompareImmediate(R9, Class::kNoTypeArguments); | 1753 __ CompareImmediate(R9, Class::kNoTypeArguments); |
| 1755 __ b(&has_no_type_arguments, EQ); | 1754 __ b(&has_no_type_arguments, EQ); |
| 1756 __ add(R9, R0, Operand(R9, LSL, 2)); | 1755 __ add(R9, R0, Operand(R9, LSL, 2)); |
| 1757 __ ldr(R4, FieldAddress(R9, 0)); | 1756 __ ldr(R4, FieldAddress(R9, 0)); |
| 1758 __ Bind(&has_no_type_arguments); | 1757 __ Bind(&has_no_type_arguments); |
| 1759 } | 1758 } |
| 1760 __ LoadClassId(R3, R0); | 1759 __ LoadClassId(R3, R0); |
| 1761 // R0: instance. | 1760 // R0: instance. |
| 1762 // R1: instantiator type arguments or NULL. | 1761 // R1: instantiator type arguments or NULL. |
| 1763 // R2: SubtypeTestCache. | 1762 // R2: SubtypeTestCache. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1785 } else { | 1784 } else { |
| 1786 __ b(&next_iteration, NE); | 1785 __ b(&next_iteration, NE); |
| 1787 __ ldr(R9, | 1786 __ ldr(R9, |
| 1788 Address(R2, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); | 1787 Address(R2, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); |
| 1789 __ cmp(R9, Operand(R4)); | 1788 __ cmp(R9, Operand(R4)); |
| 1790 if (n == 2) { | 1789 if (n == 2) { |
| 1791 __ b(&found, EQ); | 1790 __ b(&found, EQ); |
| 1792 } else { | 1791 } else { |
| 1793 __ b(&next_iteration, NE); | 1792 __ b(&next_iteration, NE); |
| 1794 __ ldr(R9, Address(R2, kWordSize * | 1793 __ ldr(R9, Address(R2, kWordSize * |
| 1795 SubtypeTestCache::kInstantiatorTypeArguments)); | 1794 SubtypeTestCache::kInstantiatorTypeArguments)); |
| 1796 __ cmp(R9, Operand(R1)); | 1795 __ cmp(R9, Operand(R1)); |
| 1797 __ b(&found, EQ); | 1796 __ b(&found, EQ); |
| 1798 } | 1797 } |
| 1799 } | 1798 } |
| 1800 __ Bind(&next_iteration); | 1799 __ Bind(&next_iteration); |
| 1801 __ AddImmediate(R2, kWordSize * SubtypeTestCache::kTestEntryLength); | 1800 __ AddImmediate(R2, kWordSize * SubtypeTestCache::kTestEntryLength); |
| 1802 __ b(&loop); | 1801 __ b(&loop); |
| 1803 // Fall through to not found. | 1802 // Fall through to not found. |
| 1804 __ Bind(¬_found); | 1803 __ Bind(¬_found); |
| 1805 __ LoadObject(R1, Object::null_object()); | 1804 __ LoadObject(R1, Object::null_object()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1856 // R0: program_counter. | 1855 // R0: program_counter. |
| 1857 // R1: stack_pointer. | 1856 // R1: stack_pointer. |
| 1858 // R2: frame_pointer. | 1857 // R2: frame_pointer. |
| 1859 // R3: error object. | 1858 // R3: error object. |
| 1860 // SP + 0: address of stacktrace object. | 1859 // SP + 0: address of stacktrace object. |
| 1861 // SP + 4: thread. | 1860 // SP + 4: thread. |
| 1862 // Does not return. | 1861 // Does not return. |
| 1863 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { | 1862 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { |
| 1864 ASSERT(kExceptionObjectReg == R0); | 1863 ASSERT(kExceptionObjectReg == R0); |
| 1865 ASSERT(kStackTraceObjectReg == R1); | 1864 ASSERT(kStackTraceObjectReg == R1); |
| 1866 __ mov(IP, Operand(R1)); // Copy Stack pointer into IP. | 1865 __ mov(IP, Operand(R1)); // Copy Stack pointer into IP. |
| 1867 __ mov(LR, Operand(R0)); // Program counter. | 1866 __ mov(LR, Operand(R0)); // Program counter. |
| 1868 __ mov(R0, Operand(R3)); // Exception object. | 1867 __ mov(R0, Operand(R3)); // Exception object. |
| 1869 __ ldr(R1, Address(SP, 0)); // StackTrace object. | 1868 __ ldr(R1, Address(SP, 0)); // StackTrace object. |
| 1870 __ ldr(THR, Address(SP, 4)); // Thread. | 1869 __ ldr(THR, Address(SP, 4)); // Thread. |
| 1871 __ mov(FP, Operand(R2)); // Frame_pointer. | 1870 __ mov(FP, Operand(R2)); // Frame_pointer. |
| 1872 __ mov(SP, Operand(IP)); // Set Stack pointer. | 1871 __ mov(SP, Operand(IP)); // Set Stack pointer. |
| 1873 // Set the tag. | 1872 // Set the tag. |
| 1874 __ LoadImmediate(R2, VMTag::kDartTagId); | 1873 __ LoadImmediate(R2, VMTag::kDartTagId); |
| 1875 __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset()); | 1874 __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset()); |
| 1876 // Clear top exit frame. | 1875 // Clear top exit frame. |
| 1877 __ LoadImmediate(R2, 0); | 1876 __ LoadImmediate(R2, 0); |
| 1878 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); | 1877 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); |
| 1879 // Restore the pool pointer. | 1878 // Restore the pool pointer. |
| 1880 __ RestoreCodePointer(); | 1879 __ RestoreCodePointer(); |
| 1881 __ LoadPoolPointer(); | 1880 __ LoadPoolPointer(); |
| 1882 __ bx(LR); // Jump to the exception handler code. | 1881 __ bx(LR); // Jump to the exception handler code. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1951 __ cmp(temp, Operand(IP)); | 1950 __ cmp(temp, Operand(IP)); |
| 1952 __ b(&done); | 1951 __ b(&done); |
| 1953 | 1952 |
| 1954 __ Bind(&check_bigint); | 1953 __ Bind(&check_bigint); |
| 1955 __ CompareClassId(left, kBigintCid, temp); | 1954 __ CompareClassId(left, kBigintCid, temp); |
| 1956 __ b(&reference_compare, NE); | 1955 __ b(&reference_compare, NE); |
| 1957 __ CompareClassId(right, kBigintCid, temp); | 1956 __ CompareClassId(right, kBigintCid, temp); |
| 1958 __ b(&done, NE); | 1957 __ b(&done, NE); |
| 1959 __ EnterStubFrame(); | 1958 __ EnterStubFrame(); |
| 1960 __ ReserveAlignedFrameSpace(2 * kWordSize); | 1959 __ ReserveAlignedFrameSpace(2 * kWordSize); |
| 1961 __ stm(IA, SP, (1 << R0) | (1 << R1)); | 1960 __ stm(IA, SP, (1 << R0) | (1 << R1)); |
| 1962 __ CallRuntime(kBigintCompareRuntimeEntry, 2); | 1961 __ CallRuntime(kBigintCompareRuntimeEntry, 2); |
| 1963 // Result in R0, 0 means equal. | 1962 // Result in R0, 0 means equal. |
| 1964 __ LeaveStubFrame(); | 1963 __ LeaveStubFrame(); |
| 1965 __ cmp(R0, Operand(0)); | 1964 __ cmp(R0, Operand(0)); |
| 1966 __ b(&done); | 1965 __ b(&done); |
| 1967 | 1966 |
| 1968 __ Bind(&reference_compare); | 1967 __ Bind(&reference_compare); |
| 1969 __ cmp(left, Operand(right)); | 1968 __ cmp(left, Operand(right)); |
| 1970 __ Bind(&done); | 1969 __ Bind(&done); |
| 1971 } | 1970 } |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2242 } | 2241 } |
| 2243 | 2242 |
| 2244 | 2243 |
| 2245 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2244 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2246 __ bkpt(0); | 2245 __ bkpt(0); |
| 2247 } | 2246 } |
| 2248 | 2247 |
| 2249 } // namespace dart | 2248 } // namespace dart |
| 2250 | 2249 |
| 2251 #endif // defined TARGET_ARCH_ARM | 2250 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |