| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/heap.h" | 13 #include "vm/heap.h" |
| 14 #include "vm/instructions.h" | 14 #include "vm/instructions.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/stack_frame.h" | 16 #include "vm/stack_frame.h" |
| 17 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 18 #include "vm/tags.h" | 18 #include "vm/tags.h" |
| 19 | 19 |
| 20 #define __ assembler-> | 20 #define __ assembler-> |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 25 DEFINE_FLAG(bool, use_slow_path, false, |
| 26 "Set to true for debugging & verifying the slow paths."); |
| 27 |
| 24 // Input parameters: | 28 // Input parameters: |
| 25 // LR : return address. | 29 // LR : return address. |
| 26 // SP : address of last argument in argument array. | 30 // SP : address of last argument in argument array. |
| 27 // SP + 8*R4 - 8 : address of first argument in argument array. | 31 // SP + 8*R4 - 8 : address of first argument in argument array. |
| 28 // SP + 8*R4 : address of return value. | 32 // SP + 8*R4 : address of return value. |
| 29 // R5 : address of the runtime function to call. | 33 // R5 : address of the runtime function to call. |
| 30 // R4 : number of arguments to the call. | 34 // R4 : number of arguments to the call. |
| 31 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 35 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 32 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 36 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 33 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 37 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 __ LeaveFrame(); | 126 __ LeaveFrame(); |
| 123 __ ret(); | 127 __ ret(); |
| 124 } | 128 } |
| 125 | 129 |
| 126 | 130 |
| 127 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) { | 131 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) { |
| 128 __ Stop("GeneratePrintStopMessageStub"); | 132 __ Stop("GeneratePrintStopMessageStub"); |
| 129 } | 133 } |
| 130 | 134 |
| 131 | 135 |
| 136 // Input parameters: |
| 137 // LR : return address. |
| 138 // SP : address of return value. |
| 139 // R5 : address of the native function to call. |
| 140 // R2 : address of first argument in argument array. |
| 141 // R1 : argc_tag including number of arguments and function kind. |
| 132 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 142 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
| 133 __ Stop("GenerateCallNativeCFunctionStub"); | 143 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 144 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 145 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 146 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 147 |
| 148 __ EnterFrame(0); |
| 149 |
| 150 // Load current Isolate pointer from Context structure into R0. |
| 151 __ LoadFieldFromOffset(R0, CTX, Context::isolate_offset()); |
| 152 |
| 153 // Save exit frame information to enable stack walking as we are about |
| 154 // to transition to native code. |
| 155 __ StoreToOffset(SP, R0, Isolate::top_exit_frame_info_offset()); |
| 156 |
| 157 // Save current Context pointer into Isolate structure. |
| 158 __ StoreToOffset(CTX, R0, Isolate::top_context_offset()); |
| 159 |
| 160 // Cache Isolate pointer into CTX while executing native code. |
| 161 __ mov(CTX, R0); |
| 162 |
| 163 #if defined(DEBUG) |
| 164 { Label ok; |
| 165 // Check that we are always entering from Dart code. |
| 166 __ LoadFromOffset(R6, CTX, Isolate::vm_tag_offset()); |
| 167 __ CompareImmediate(R6, VMTag::kScriptTagId, PP); |
| 168 __ b(&ok, EQ); |
| 169 __ Stop("Not coming from Dart code."); |
| 170 __ Bind(&ok); |
| 171 } |
| 172 #endif |
| 173 |
| 174 // Mark that the isolate is executing Native code. |
| 175 __ StoreToOffset(R5, CTX, Isolate::vm_tag_offset()); |
| 176 |
| 177 // Reserve space for the native arguments structure passed on the stack (the |
| 178 // outgoing pointer parameter to the native arguments structure is passed in |
| 179 // R0) and align frame before entering the C++ world. |
| 180 __ ReserveAlignedFrameSpace(sizeof(NativeArguments)); |
| 181 |
| 182 // Initialize NativeArguments structure and call native function. |
| 183 // Registers R0, R1, R2, and R3 are used. |
| 184 |
| 185 ASSERT(isolate_offset == 0 * kWordSize); |
| 186 // Set isolate in NativeArgs: R0 already contains CTX. |
| 187 |
| 188 // There are no native calls to closures, so we do not need to set the tag |
| 189 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 190 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 191 // Set argc in NativeArguments: R1 already contains argc. |
| 192 |
| 193 ASSERT(argv_offset == 2 * kWordSize); |
| 194 // Set argv in NativeArguments: R2 already contains argv. |
| 195 |
| 196 // Set retval in NativeArgs. |
| 197 ASSERT(retval_offset == 3 * kWordSize); |
| 198 __ AddImmediate(R3, FP, 2 * kWordSize, PP); |
| 199 |
| 200 // TODO(regis): Should we pass the structure by value as in runtime calls? |
| 201 // It would require changing Dart API for native functions. |
| 202 // For now, space is reserved on the stack and we pass a pointer to it. |
| 203 __ StoreToOffset(R0, SP, isolate_offset); |
| 204 __ StoreToOffset(R1, SP, argc_tag_offset); |
| 205 __ StoreToOffset(R2, SP, argv_offset); |
| 206 __ StoreToOffset(R3, SP, retval_offset); |
| 207 __ mov(R0, SP); // Pass the pointer to the NativeArguments. |
| 208 |
| 209 // Call native function (setsup scope if not leaf function). |
| 210 Label leaf_call; |
| 211 Label done; |
| 212 __ TestImmediate(R1, NativeArguments::AutoSetupScopeMask(), PP); |
| 213 __ b(&leaf_call, EQ); |
| 214 |
| 215 __ mov(R1, R5); // Pass the function entrypoint to call. |
| 216 // Call native function invocation wrapper or redirection via simulator. |
| 217 #if defined(USING_SIMULATOR) |
| 218 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); |
| 219 entry = Simulator::RedirectExternalReference( |
| 220 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); |
| 221 __ LoadImmediate(R2, entry, PP); |
| 222 __ blr(R2); |
| 223 #else |
| 224 __ BranchLink(&NativeEntry::NativeCallWrapperLabel()); |
| 225 #endif |
| 226 __ b(&done); |
| 227 |
| 228 __ Bind(&leaf_call); |
| 229 // Call native function or redirection via simulator. |
| 230 __ blr(R5); |
| 231 |
| 232 __ Bind(&done); |
| 233 |
| 234 // Mark that the isolate is executing Dart code. |
| 235 __ LoadImmediate(R2, VMTag::kScriptTagId, PP); |
| 236 __ StoreToOffset(R2, CTX, Isolate::vm_tag_offset()); |
| 237 |
| 238 // Reset exit frame information in Isolate structure. |
| 239 __ LoadImmediate(R2, 0, PP); |
| 240 __ StoreToOffset(R2, CTX, Isolate::top_exit_frame_info_offset()); |
| 241 |
| 242 // Load Context pointer from Isolate structure into R2. |
| 243 __ LoadFromOffset(R2, CTX, Isolate::top_context_offset()); |
| 244 |
| 245 // Reset Context pointer in Isolate structure. |
| 246 __ LoadObject(R3, Object::null_object(), PP); |
| 247 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); |
| 248 |
| 249 // Cache Context pointer into CTX while executing Dart code. |
| 250 __ mov(CTX, R2); |
| 251 |
| 252 __ LeaveFrame(); |
| 253 __ ret(); |
| 134 } | 254 } |
| 135 | 255 |
| 136 | 256 |
| 137 // Input parameters: | 257 // Input parameters: |
| 138 // LR : return address. | 258 // LR : return address. |
| 139 // SP : address of return value. | 259 // SP : address of return value. |
| 140 // R5 : address of the native function to call. | 260 // R5 : address of the native function to call. |
| 141 // R2 : address of first argument in argument array. | 261 // R2 : address of first argument in argument array. |
| 142 // R1 : argc_tag including number of arguments and function kind. | 262 // R1 : argc_tag including number of arguments and function kind. |
| 143 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { | 263 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 | 596 |
| 477 __ EnterCallRuntimeFrame(0 * kWordSize); | 597 __ EnterCallRuntimeFrame(0 * kWordSize); |
| 478 __ LoadFieldFromOffset(R0, CTX, Context::isolate_offset()); | 598 __ LoadFieldFromOffset(R0, CTX, Context::isolate_offset()); |
| 479 __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1); | 599 __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1); |
| 480 // Restore callee-saved registers, tear down frame. | 600 // Restore callee-saved registers, tear down frame. |
| 481 __ LeaveCallRuntimeFrame(); | 601 __ LeaveCallRuntimeFrame(); |
| 482 __ ret(); | 602 __ ret(); |
| 483 } | 603 } |
| 484 | 604 |
| 485 | 605 |
| 606 // Called for inline allocation of objects. |
| 607 // Input parameters: |
| 608 // LR : return address. |
| 609 // SP + 0 : type arguments object (only if class is parameterized). |
| 486 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, | 610 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
| 487 const Class& cls) { | 611 const Class& cls) { |
| 488 __ Stop("GenerateAllocationStubForClass"); | 612 // The generated code is different if the class is parameterized. |
| 613 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
| 614 ASSERT(!is_cls_parameterized || |
| 615 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
| 616 // kInlineInstanceSize is a constant used as a threshold for determining |
| 617 // when the object initialization should be done as a loop or as |
| 618 // straight line code. |
| 619 const int kInlineInstanceSize = 12; |
| 620 const intptr_t instance_size = cls.instance_size(); |
| 621 ASSERT(instance_size > 0); |
| 622 if (is_cls_parameterized) { |
| 623 __ ldr(R1, Address(SP)); |
| 624 // R1: instantiated type arguments. |
| 625 } |
| 626 if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size)) { |
| 627 Label slow_case; |
| 628 // Allocate the object and update top to point to |
| 629 // next object start and initialize the allocated object. |
| 630 // R1: instantiated type arguments (if is_cls_parameterized). |
| 631 Heap* heap = Isolate::Current()->heap(); |
| 632 __ LoadImmediate(R5, heap->TopAddress(), PP); |
| 633 __ ldr(R2, Address(R5)); |
| 634 __ AddImmediate(R3, R2, instance_size, PP); |
| 635 // Check if the allocation fits into the remaining space. |
| 636 // R2: potential new object start. |
| 637 // R3: potential next object start. |
| 638 __ LoadImmediate(TMP, heap->EndAddress(), PP); |
| 639 __ ldr(TMP, Address(TMP)); |
| 640 __ CompareRegisters(R3, TMP); |
| 641 if (FLAG_use_slow_path) { |
| 642 __ b(&slow_case); |
| 643 } else { |
| 644 __ b(&slow_case, CS); // Unsigned higher or equal. |
| 645 } |
| 646 __ str(R3, Address(R5)); |
| 647 __ UpdateAllocationStats(cls.id(), R5); |
| 648 |
| 649 // R2: new object start. |
| 650 // R3: next object start. |
| 651 // R1: new object type arguments (if is_cls_parameterized). |
| 652 // Set the tags. |
| 653 uword tags = 0; |
| 654 tags = RawObject::SizeTag::update(instance_size, tags); |
| 655 ASSERT(cls.id() != kIllegalCid); |
| 656 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 657 __ LoadImmediate(R0, tags, PP); |
| 658 __ StoreToOffset(R0, R2, Instance::tags_offset()); |
| 659 |
| 660 // Initialize the remaining words of the object. |
| 661 __ LoadObject(R0, Object::null_object(), PP); |
| 662 |
| 663 // R0: raw null. |
| 664 // R2: new object start. |
| 665 // R3: next object start. |
| 666 // R1: new object type arguments (if is_cls_parameterized). |
| 667 // First try inlining the initialization without a loop. |
| 668 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
| 669 // Check if the object contains any non-header fields. |
| 670 // Small objects are initialized using a consecutive set of writes. |
| 671 for (intptr_t current_offset = Instance::NextFieldOffset(); |
| 672 current_offset < instance_size; |
| 673 current_offset += kWordSize) { |
| 674 __ StoreToOffset(R0, R2, current_offset); |
| 675 } |
| 676 } else { |
| 677 __ AddImmediate(R4, R2, Instance::NextFieldOffset(), PP); |
| 678 // Loop until the whole object is initialized. |
| 679 // R0: raw null. |
| 680 // R2: new object. |
| 681 // R3: next object start. |
| 682 // R4: next word to be initialized. |
| 683 // R1: new object type arguments (if is_cls_parameterized). |
| 684 Label init_loop; |
| 685 Label done; |
| 686 __ Bind(&init_loop); |
| 687 __ CompareRegisters(R4, R3); |
| 688 __ b(&done, CS); |
| 689 __ str(R0, Address(R4)); |
| 690 __ AddImmediate(R4, R4, kWordSize, PP); |
| 691 __ b(&init_loop); |
| 692 __ Bind(&done); |
| 693 } |
| 694 if (is_cls_parameterized) { |
| 695 // R1: new object type arguments. |
| 696 // Set the type arguments in the new object. |
| 697 __ StoreToOffset(R1, R2, cls.type_arguments_field_offset()); |
| 698 } |
| 699 // Done allocating and initializing the instance. |
| 700 // R2: new object still missing its heap tag. |
| 701 __ add(R0, R2, Operand(kHeapObjectTag)); |
| 702 // R0: new object. |
| 703 __ ret(); |
| 704 |
| 705 __ Bind(&slow_case); |
| 706 } |
| 707 // If is_cls_parameterized: |
| 708 // R1: new object type arguments. |
| 709 // Create a stub frame as we are pushing some objects on the stack before |
| 710 // calling into the runtime. |
| 711 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. |
| 712 // Setup space on stack for return value. |
| 713 __ PushObject(Object::null_object(), PP); |
| 714 __ PushObject(cls, PP); // Push class of object to be allocated. |
| 715 if (is_cls_parameterized) { |
| 716 // Push type arguments. |
| 717 __ Push(R1); |
| 718 } else { |
| 719 // Push null type arguments. |
| 720 __ Push(R2); |
| 721 } |
| 722 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 723 __ Drop(2); // Pop arguments. |
| 724 __ Pop(R0); // Pop result (newly allocated object). |
| 725 // R0: new object |
| 726 // Restore the frame pointer. |
| 727 __ LeaveStubFrame(); |
| 728 __ ret(); |
| 489 } | 729 } |
| 490 | 730 |
| 491 | 731 |
| 492 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 732 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
| 493 __ Stop("GenerateCallNoSuchMethodFunctionStub"); | 733 __ Stop("GenerateCallNoSuchMethodFunctionStub"); |
| 494 } | 734 } |
| 495 | 735 |
| 496 | 736 |
| 497 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 737 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 498 __ Stop("GenerateOptimizedUsageCounterIncrement"); | 738 __ Stop("GenerateOptimizedUsageCounterIncrement"); |
| (...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 | 1240 |
| 1001 | 1241 |
| 1002 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( | 1242 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( |
| 1003 Assembler* assembler) { | 1243 Assembler* assembler) { |
| 1004 __ Stop("GenerateOptimizedIdenticalWithNumberCheckStub"); | 1244 __ Stop("GenerateOptimizedIdenticalWithNumberCheckStub"); |
| 1005 } | 1245 } |
| 1006 | 1246 |
| 1007 } // namespace dart | 1247 } // namespace dart |
| 1008 | 1248 |
| 1009 #endif // defined TARGET_ARCH_ARM64 | 1249 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |