| 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" |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 // Save current Context pointer into Isolate structure. | 157 // Save current Context pointer into Isolate structure. |
| 158 __ StoreToOffset(CTX, R0, Isolate::top_context_offset()); | 158 __ StoreToOffset(CTX, R0, Isolate::top_context_offset()); |
| 159 | 159 |
| 160 // Cache Isolate pointer into CTX while executing native code. | 160 // Cache Isolate pointer into CTX while executing native code. |
| 161 __ mov(CTX, R0); | 161 __ mov(CTX, R0); |
| 162 | 162 |
| 163 #if defined(DEBUG) | 163 #if defined(DEBUG) |
| 164 { Label ok; | 164 { Label ok; |
| 165 // Check that we are always entering from Dart code. | 165 // Check that we are always entering from Dart code. |
| 166 __ LoadFromOffset(R6, CTX, Isolate::vm_tag_offset()); | 166 __ LoadFromOffset(R6, CTX, Isolate::vm_tag_offset()); |
| 167 __ CompareImmediate(R6, VMTag::kScriptTagId, PP); | 167 __ CompareImmediate(R6, VMTag::kScriptTagId, kNoRegister); |
| 168 __ b(&ok, EQ); | 168 __ b(&ok, EQ); |
| 169 __ Stop("Not coming from Dart code."); | 169 __ Stop("Not coming from Dart code."); |
| 170 __ Bind(&ok); | 170 __ Bind(&ok); |
| 171 } | 171 } |
| 172 #endif | 172 #endif |
| 173 | 173 |
| 174 // Mark that the isolate is executing Native code. | 174 // Mark that the isolate is executing Native code. |
| 175 __ StoreToOffset(R5, CTX, Isolate::vm_tag_offset()); | 175 __ StoreToOffset(R5, CTX, Isolate::vm_tag_offset()); |
| 176 | 176 |
| 177 // Reserve space for the native arguments structure passed on the stack (the | 177 // Reserve space for the native arguments structure passed on the stack (the |
| (...skipping 10 matching lines...) Expand all Loading... |
| 188 // There are no native calls to closures, so we do not need to set the tag | 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_. | 189 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 190 ASSERT(argc_tag_offset == 1 * kWordSize); | 190 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 191 // Set argc in NativeArguments: R1 already contains argc. | 191 // Set argc in NativeArguments: R1 already contains argc. |
| 192 | 192 |
| 193 ASSERT(argv_offset == 2 * kWordSize); | 193 ASSERT(argv_offset == 2 * kWordSize); |
| 194 // Set argv in NativeArguments: R2 already contains argv. | 194 // Set argv in NativeArguments: R2 already contains argv. |
| 195 | 195 |
| 196 // Set retval in NativeArgs. | 196 // Set retval in NativeArgs. |
| 197 ASSERT(retval_offset == 3 * kWordSize); | 197 ASSERT(retval_offset == 3 * kWordSize); |
| 198 __ AddImmediate(R3, FP, 2 * kWordSize, PP); | 198 __ AddImmediate(R3, FP, 2 * kWordSize, kNoRegister); |
| 199 | 199 |
| 200 // TODO(regis): Should we pass the structure by value as in runtime calls? | 200 // TODO(regis): Should we pass the structure by value as in runtime calls? |
| 201 // It would require changing Dart API for native functions. | 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. | 202 // For now, space is reserved on the stack and we pass a pointer to it. |
| 203 __ StoreToOffset(R0, SP, isolate_offset); | 203 __ StoreToOffset(R0, SP, isolate_offset); |
| 204 __ StoreToOffset(R1, SP, argc_tag_offset); | 204 __ StoreToOffset(R1, SP, argc_tag_offset); |
| 205 __ StoreToOffset(R2, SP, argv_offset); | 205 __ StoreToOffset(R2, SP, argv_offset); |
| 206 __ StoreToOffset(R3, SP, retval_offset); | 206 __ StoreToOffset(R3, SP, retval_offset); |
| 207 __ mov(R0, SP); // Pass the pointer to the NativeArguments. | 207 __ mov(R0, SP); // Pass the pointer to the NativeArguments. |
| 208 | 208 |
| 209 // Call native function (setsup scope if not leaf function). | 209 // Call native function (setsup scope if not leaf function). |
| 210 Label leaf_call; | 210 Label leaf_call; |
| 211 Label done; | 211 Label done; |
| 212 __ TestImmediate(R1, NativeArguments::AutoSetupScopeMask(), PP); | 212 __ TestImmediate(R1, NativeArguments::AutoSetupScopeMask(), kNoRegister); |
| 213 __ b(&leaf_call, EQ); | 213 __ b(&leaf_call, EQ); |
| 214 | 214 |
| 215 __ mov(R1, R5); // Pass the function entrypoint to call. | 215 __ mov(R1, R5); // Pass the function entrypoint to call. |
| 216 // Call native function invocation wrapper or redirection via simulator. | 216 // Call native function invocation wrapper or redirection via simulator. |
| 217 #if defined(USING_SIMULATOR) | 217 #if defined(USING_SIMULATOR) |
| 218 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); | 218 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); |
| 219 entry = Simulator::RedirectExternalReference( | 219 entry = Simulator::RedirectExternalReference( |
| 220 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); | 220 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); |
| 221 __ LoadImmediate(R2, entry, PP); | 221 __ LoadImmediate(R2, entry, kNoRegister); |
| 222 __ blr(R2); | 222 __ blr(R2); |
| 223 #else | 223 #else |
| 224 __ BranchLink(&NativeEntry::NativeCallWrapperLabel()); | 224 __ BranchLink(&NativeEntry::NativeCallWrapperLabel()); |
| 225 #endif | 225 #endif |
| 226 __ b(&done); | 226 __ b(&done); |
| 227 | 227 |
| 228 __ Bind(&leaf_call); | 228 __ Bind(&leaf_call); |
| 229 // Call native function or redirection via simulator. | 229 // Call native function or redirection via simulator. |
| 230 __ blr(R5); | 230 __ blr(R5); |
| 231 | 231 |
| 232 __ Bind(&done); | 232 __ Bind(&done); |
| 233 | 233 |
| 234 // Mark that the isolate is executing Dart code. | 234 // Mark that the isolate is executing Dart code. |
| 235 __ LoadImmediate(R2, VMTag::kScriptTagId, PP); | 235 __ LoadImmediate(R2, VMTag::kScriptTagId, kNoRegister); |
| 236 __ StoreToOffset(R2, CTX, Isolate::vm_tag_offset()); | 236 __ StoreToOffset(R2, CTX, Isolate::vm_tag_offset()); |
| 237 | 237 |
| 238 // Reset exit frame information in Isolate structure. | 238 // Reset exit frame information in Isolate structure. |
| 239 __ LoadImmediate(R2, 0, PP); | 239 __ LoadImmediate(R2, 0, kNoRegister); |
| 240 __ StoreToOffset(R2, CTX, Isolate::top_exit_frame_info_offset()); | 240 __ StoreToOffset(R2, CTX, Isolate::top_exit_frame_info_offset()); |
| 241 | 241 |
| 242 // Load Context pointer from Isolate structure into R2. | 242 // Load Context pointer from Isolate structure into R2. |
| 243 __ LoadFromOffset(R2, CTX, Isolate::top_context_offset()); | 243 __ LoadFromOffset(R2, CTX, Isolate::top_context_offset()); |
| 244 | 244 |
| 245 // Reset Context pointer in Isolate structure. | 245 // Reset Context pointer in Isolate structure. |
| 246 __ LoadObject(R3, Object::null_object(), PP); | 246 __ LoadObject(R3, Object::null_object(), PP); |
| 247 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); | 247 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); |
| 248 | 248 |
| 249 // Cache Context pointer into CTX while executing Dart code. | 249 // Cache Context pointer into CTX while executing Dart code. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 279 // Save current Context pointer into Isolate structure. | 279 // Save current Context pointer into Isolate structure. |
| 280 __ StoreToOffset(CTX, R0, Isolate::top_context_offset()); | 280 __ StoreToOffset(CTX, R0, Isolate::top_context_offset()); |
| 281 | 281 |
| 282 // Cache Isolate pointer into CTX while executing native code. | 282 // Cache Isolate pointer into CTX while executing native code. |
| 283 __ mov(CTX, R0); | 283 __ mov(CTX, R0); |
| 284 | 284 |
| 285 #if defined(DEBUG) | 285 #if defined(DEBUG) |
| 286 { Label ok; | 286 { Label ok; |
| 287 // Check that we are always entering from Dart code. | 287 // Check that we are always entering from Dart code. |
| 288 __ LoadFromOffset(R6, CTX, Isolate::vm_tag_offset()); | 288 __ LoadFromOffset(R6, CTX, Isolate::vm_tag_offset()); |
| 289 __ CompareImmediate(R6, VMTag::kScriptTagId, PP); | 289 __ CompareImmediate(R6, VMTag::kScriptTagId, kNoRegister); |
| 290 __ b(&ok, EQ); | 290 __ b(&ok, EQ); |
| 291 __ Stop("Not coming from Dart code."); | 291 __ Stop("Not coming from Dart code."); |
| 292 __ Bind(&ok); | 292 __ Bind(&ok); |
| 293 } | 293 } |
| 294 #endif | 294 #endif |
| 295 | 295 |
| 296 // Mark that the isolate is executing Native code. | 296 // Mark that the isolate is executing Native code. |
| 297 __ StoreToOffset(R5, CTX, Isolate::vm_tag_offset()); | 297 __ StoreToOffset(R5, CTX, Isolate::vm_tag_offset()); |
| 298 | 298 |
| 299 // Reserve space for the native arguments structure passed on the stack (the | 299 // Reserve space for the native arguments structure passed on the stack (the |
| (...skipping 10 matching lines...) Expand all Loading... |
| 310 // There are no native calls to closures, so we do not need to set the tag | 310 // There are no native calls to closures, so we do not need to set the tag |
| 311 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 311 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 312 ASSERT(argc_tag_offset == 1 * kWordSize); | 312 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 313 // Set argc in NativeArguments: R1 already contains argc. | 313 // Set argc in NativeArguments: R1 already contains argc. |
| 314 | 314 |
| 315 ASSERT(argv_offset == 2 * kWordSize); | 315 ASSERT(argv_offset == 2 * kWordSize); |
| 316 // Set argv in NativeArguments: R2 already contains argv. | 316 // Set argv in NativeArguments: R2 already contains argv. |
| 317 | 317 |
| 318 // Set retval in NativeArgs. | 318 // Set retval in NativeArgs. |
| 319 ASSERT(retval_offset == 3 * kWordSize); | 319 ASSERT(retval_offset == 3 * kWordSize); |
| 320 __ AddImmediate(R3, FP, 2 * kWordSize, PP); | 320 __ AddImmediate(R3, FP, 2 * kWordSize, kNoRegister); |
| 321 | 321 |
| 322 // TODO(regis): Should we pass the structure by value as in runtime calls? | 322 // TODO(regis): Should we pass the structure by value as in runtime calls? |
| 323 // It would require changing Dart API for native functions. | 323 // It would require changing Dart API for native functions. |
| 324 // For now, space is reserved on the stack and we pass a pointer to it. | 324 // For now, space is reserved on the stack and we pass a pointer to it. |
| 325 __ StoreToOffset(R0, SP, isolate_offset); | 325 __ StoreToOffset(R0, SP, isolate_offset); |
| 326 __ StoreToOffset(R1, SP, argc_tag_offset); | 326 __ StoreToOffset(R1, SP, argc_tag_offset); |
| 327 __ StoreToOffset(R2, SP, argv_offset); | 327 __ StoreToOffset(R2, SP, argv_offset); |
| 328 __ StoreToOffset(R3, SP, retval_offset); | 328 __ StoreToOffset(R3, SP, retval_offset); |
| 329 __ mov(R0, SP); // Pass the pointer to the NativeArguments. | 329 __ mov(R0, SP); // Pass the pointer to the NativeArguments. |
| 330 | 330 |
| 331 // Call native function or redirection via simulator. | 331 // Call native function or redirection via simulator. |
| 332 __ blr(R5); | 332 __ blr(R5); |
| 333 | 333 |
| 334 // Mark that the isolate is executing Dart code. | 334 // Mark that the isolate is executing Dart code. |
| 335 __ LoadImmediate(R2, VMTag::kScriptTagId, PP); | 335 __ LoadImmediate(R2, VMTag::kScriptTagId, kNoRegister); |
| 336 __ StoreToOffset(R2, CTX, Isolate::vm_tag_offset()); | 336 __ StoreToOffset(R2, CTX, Isolate::vm_tag_offset()); |
| 337 | 337 |
| 338 // Reset exit frame information in Isolate structure. | 338 // Reset exit frame information in Isolate structure. |
| 339 __ LoadImmediate(R2, 0, PP); | 339 __ LoadImmediate(R2, 0, kNoRegister); |
| 340 __ StoreToOffset(R2, CTX, Isolate::top_exit_frame_info_offset()); | 340 __ StoreToOffset(R2, CTX, Isolate::top_exit_frame_info_offset()); |
| 341 | 341 |
| 342 // Load Context pointer from Isolate structure into R2. | 342 // Load Context pointer from Isolate structure into R2. |
| 343 __ LoadFromOffset(R2, CTX, Isolate::top_context_offset()); | 343 __ LoadFromOffset(R2, CTX, Isolate::top_context_offset()); |
| 344 | 344 |
| 345 // Reset Context pointer in Isolate structure. | 345 // Reset Context pointer in Isolate structure. |
| 346 __ LoadObject(R3, Object::null_object(), PP); | 346 __ LoadObject(R3, Object::null_object(), PP); |
| 347 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); | 347 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); |
| 348 | 348 |
| 349 // Cache Context pointer into CTX while executing Dart code. | 349 // Cache Context pointer into CTX while executing Dart code. |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 | 565 |
| 566 // Load the isolate out of the context. | 566 // Load the isolate out of the context. |
| 567 // Spilled: R1, R2, R3. | 567 // Spilled: R1, R2, R3. |
| 568 // R0: address being stored. | 568 // R0: address being stored. |
| 569 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); | 569 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); |
| 570 | 570 |
| 571 // Load the StoreBuffer block out of the isolate. Then load top_ out of the | 571 // Load the StoreBuffer block out of the isolate. Then load top_ out of the |
| 572 // StoreBufferBlock and add the address to the pointers_. | 572 // StoreBufferBlock and add the address to the pointers_. |
| 573 // R1: isolate. | 573 // R1: isolate. |
| 574 __ LoadFromOffset(R1, R1, Isolate::store_buffer_offset()); | 574 __ LoadFromOffset(R1, R1, Isolate::store_buffer_offset()); |
| 575 __ LoadFromOffset(R2, R1, StoreBufferBlock::top_offset()); | 575 __ LoadFromOffset(R2, R1, StoreBufferBlock::top_offset(), kUnsignedWord); |
| 576 __ add(R3, R1, Operand(R2, LSL, 3)); | 576 __ add(R3, R1, Operand(R2, LSL, 3)); |
| 577 __ StoreToOffset(R0, R3, StoreBufferBlock::pointers_offset()); | 577 __ StoreToOffset(R0, R3, StoreBufferBlock::pointers_offset()); |
| 578 | 578 |
| 579 // Increment top_ and check for overflow. | 579 // Increment top_ and check for overflow. |
| 580 // R2: top_. | 580 // R2: top_. |
| 581 // R1: StoreBufferBlock. | 581 // R1: StoreBufferBlock. |
| 582 Label L; | 582 Label L; |
| 583 __ add(R2, R2, Operand(1)); | 583 __ add(R2, R2, Operand(1)); |
| 584 __ StoreToOffset(R2, R1, StoreBufferBlock::top_offset()); | 584 __ StoreToOffset(R2, R1, StoreBufferBlock::top_offset(), kUnsignedWord); |
| 585 __ CompareImmediate(R2, StoreBufferBlock::kSize, PP); | 585 __ CompareImmediate(R2, StoreBufferBlock::kSize, kNoRegister); |
| 586 // Restore values. | 586 // Restore values. |
| 587 __ Pop(R3); | 587 __ Pop(R3); |
| 588 __ Pop(R2); | 588 __ Pop(R2); |
| 589 __ Pop(R1); | 589 __ Pop(R1); |
| 590 __ b(&L, EQ); | 590 __ b(&L, EQ); |
| 591 __ ret(); | 591 __ ret(); |
| 592 | 592 |
| 593 // Handle overflow: Call the runtime leaf function. | 593 // Handle overflow: Call the runtime leaf function. |
| 594 __ Bind(&L); | 594 __ Bind(&L); |
| 595 // Setup frame, push callee-saved registers. | 595 // Setup frame, push callee-saved registers. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 622 if (is_cls_parameterized) { | 622 if (is_cls_parameterized) { |
| 623 __ ldr(R1, Address(SP)); | 623 __ ldr(R1, Address(SP)); |
| 624 // R1: instantiated type arguments. | 624 // R1: instantiated type arguments. |
| 625 } | 625 } |
| 626 if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size)) { | 626 if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size)) { |
| 627 Label slow_case; | 627 Label slow_case; |
| 628 // Allocate the object and update top to point to | 628 // Allocate the object and update top to point to |
| 629 // next object start and initialize the allocated object. | 629 // next object start and initialize the allocated object. |
| 630 // R1: instantiated type arguments (if is_cls_parameterized). | 630 // R1: instantiated type arguments (if is_cls_parameterized). |
| 631 Heap* heap = Isolate::Current()->heap(); | 631 Heap* heap = Isolate::Current()->heap(); |
| 632 __ LoadImmediate(R5, heap->TopAddress(), PP); | 632 __ LoadImmediate(R5, heap->TopAddress(), kNoRegister); |
| 633 __ ldr(R2, Address(R5)); | 633 __ ldr(R2, Address(R5)); |
| 634 __ AddImmediate(R3, R2, instance_size, PP); | 634 __ AddImmediate(R3, R2, instance_size, kNoRegister); |
| 635 // Check if the allocation fits into the remaining space. | 635 // Check if the allocation fits into the remaining space. |
| 636 // R2: potential new object start. | 636 // R2: potential new object start. |
| 637 // R3: potential next object start. | 637 // R3: potential next object start. |
| 638 __ LoadImmediate(TMP, heap->EndAddress(), PP); | 638 __ LoadImmediate(TMP, heap->EndAddress(), kNoRegister); |
| 639 __ ldr(TMP, Address(TMP)); | 639 __ ldr(TMP, Address(TMP)); |
| 640 __ CompareRegisters(R3, TMP); | 640 __ CompareRegisters(R3, TMP); |
| 641 if (FLAG_use_slow_path) { | 641 if (FLAG_use_slow_path) { |
| 642 __ b(&slow_case); | 642 __ b(&slow_case); |
| 643 } else { | 643 } else { |
| 644 __ b(&slow_case, CS); // Unsigned higher or equal. | 644 __ b(&slow_case, CS); // Unsigned higher or equal. |
| 645 } | 645 } |
| 646 __ str(R3, Address(R5)); | 646 __ str(R3, Address(R5)); |
| 647 __ UpdateAllocationStats(cls.id(), R5); | 647 __ UpdateAllocationStats(cls.id(), R5, kNoRegister); |
| 648 | 648 |
| 649 // R2: new object start. | 649 // R2: new object start. |
| 650 // R3: next object start. | 650 // R3: next object start. |
| 651 // R1: new object type arguments (if is_cls_parameterized). | 651 // R1: new object type arguments (if is_cls_parameterized). |
| 652 // Set the tags. | 652 // Set the tags. |
| 653 uword tags = 0; | 653 uword tags = 0; |
| 654 tags = RawObject::SizeTag::update(instance_size, tags); | 654 tags = RawObject::SizeTag::update(instance_size, tags); |
| 655 ASSERT(cls.id() != kIllegalCid); | 655 ASSERT(cls.id() != kIllegalCid); |
| 656 tags = RawObject::ClassIdTag::update(cls.id(), tags); | 656 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 657 __ LoadImmediate(R0, tags, PP); | 657 __ LoadImmediate(R0, tags, kNoRegister); |
| 658 __ StoreToOffset(R0, R2, Instance::tags_offset()); | 658 __ StoreToOffset(R0, R2, Instance::tags_offset()); |
| 659 | 659 |
| 660 // Initialize the remaining words of the object. | 660 // Initialize the remaining words of the object. |
| 661 __ LoadObject(R0, Object::null_object(), PP); | 661 __ LoadObject(R0, Object::null_object(), PP); |
| 662 | 662 |
| 663 // R0: raw null. | 663 // R0: raw null. |
| 664 // R2: new object start. | 664 // R2: new object start. |
| 665 // R3: next object start. | 665 // R3: next object start. |
| 666 // R1: new object type arguments (if is_cls_parameterized). | 666 // R1: new object type arguments (if is_cls_parameterized). |
| 667 // First try inlining the initialization without a loop. | 667 // First try inlining the initialization without a loop. |
| 668 if (instance_size < (kInlineInstanceSize * kWordSize)) { | 668 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
| 669 // Check if the object contains any non-header fields. | 669 // Check if the object contains any non-header fields. |
| 670 // Small objects are initialized using a consecutive set of writes. | 670 // Small objects are initialized using a consecutive set of writes. |
| 671 for (intptr_t current_offset = Instance::NextFieldOffset(); | 671 for (intptr_t current_offset = Instance::NextFieldOffset(); |
| 672 current_offset < instance_size; | 672 current_offset < instance_size; |
| 673 current_offset += kWordSize) { | 673 current_offset += kWordSize) { |
| 674 __ StoreToOffset(R0, R2, current_offset); | 674 __ StoreToOffset(R0, R2, current_offset); |
| 675 } | 675 } |
| 676 } else { | 676 } else { |
| 677 __ AddImmediate(R4, R2, Instance::NextFieldOffset(), PP); | 677 __ AddImmediate(R4, R2, Instance::NextFieldOffset(), kNoRegister); |
| 678 // Loop until the whole object is initialized. | 678 // Loop until the whole object is initialized. |
| 679 // R0: raw null. | 679 // R0: raw null. |
| 680 // R2: new object. | 680 // R2: new object. |
| 681 // R3: next object start. | 681 // R3: next object start. |
| 682 // R4: next word to be initialized. | 682 // R4: next word to be initialized. |
| 683 // R1: new object type arguments (if is_cls_parameterized). | 683 // R1: new object type arguments (if is_cls_parameterized). |
| 684 Label init_loop; | 684 Label init_loop; |
| 685 Label done; | 685 Label done; |
| 686 __ Bind(&init_loop); | 686 __ Bind(&init_loop); |
| 687 __ CompareRegisters(R4, R3); | 687 __ CompareRegisters(R4, R3); |
| 688 __ b(&done, CS); | 688 __ b(&done, CS); |
| 689 __ str(R0, Address(R4)); | 689 __ str(R0, Address(R4)); |
| 690 __ AddImmediate(R4, R4, kWordSize, PP); | 690 __ AddImmediate(R4, R4, kWordSize, kNoRegister); |
| 691 __ b(&init_loop); | 691 __ b(&init_loop); |
| 692 __ Bind(&done); | 692 __ Bind(&done); |
| 693 } | 693 } |
| 694 if (is_cls_parameterized) { | 694 if (is_cls_parameterized) { |
| 695 // R1: new object type arguments. | 695 // R1: new object type arguments. |
| 696 // Set the type arguments in the new object. | 696 // Set the type arguments in the new object. |
| 697 __ StoreToOffset(R1, R2, cls.type_arguments_field_offset()); | 697 __ StoreToOffset(R1, R2, cls.type_arguments_field_offset()); |
| 698 } | 698 } |
| 699 // Done allocating and initializing the instance. | 699 // Done allocating and initializing the instance. |
| 700 // R2: new object still missing its heap tag. | 700 // R2: new object still missing its heap tag. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 | 740 |
| 741 | 741 |
| 742 // Loads function into 'temp_reg'. | 742 // Loads function into 'temp_reg'. |
| 743 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 743 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 744 Register temp_reg) { | 744 Register temp_reg) { |
| 745 Register ic_reg = R5; | 745 Register ic_reg = R5; |
| 746 Register func_reg = temp_reg; | 746 Register func_reg = temp_reg; |
| 747 ASSERT(temp_reg == R6); | 747 ASSERT(temp_reg == R6); |
| 748 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset()); | 748 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset()); |
| 749 __ LoadFieldFromOffset(R7, func_reg, Function::usage_counter_offset()); | 749 __ LoadFieldFromOffset(R7, func_reg, Function::usage_counter_offset()); |
| 750 __ AddImmediate(R7, R7, 1, PP); | 750 __ AddImmediate(R7, R7, 1, kNoRegister); |
| 751 __ StoreFieldToOffset(R7, func_reg, Function::usage_counter_offset()); | 751 __ StoreFieldToOffset(R7, func_reg, Function::usage_counter_offset()); |
| 752 } | 752 } |
| 753 | 753 |
| 754 | 754 |
| 755 // Generate inline cache check for 'num_args'. | 755 // Generate inline cache check for 'num_args'. |
| 756 // LR: return address. | 756 // LR: return address. |
| 757 // R5: inline cache data object. | 757 // R5: inline cache data object. |
| 758 // Control flow: | 758 // Control flow: |
| 759 // - If receiver is null -> jump to IC miss. | 759 // - If receiver is null -> jump to IC miss. |
| 760 // - If receiver is Smi -> load Smi class. | 760 // - If receiver is Smi -> load Smi class. |
| 761 // - If receiver is not-Smi -> load receiver's class. | 761 // - If receiver is not-Smi -> load receiver's class. |
| 762 // - Check if 'num_args' (including receiver) match any IC data group. | 762 // - Check if 'num_args' (including receiver) match any IC data group. |
| 763 // - Match found -> jump to target. | 763 // - Match found -> jump to target. |
| 764 // - Match not found -> jump to IC miss. | 764 // - Match not found -> jump to IC miss. |
| 765 void StubCode::GenerateNArgsCheckInlineCacheStub( | 765 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 766 Assembler* assembler, | 766 Assembler* assembler, |
| 767 intptr_t num_args, | 767 intptr_t num_args, |
| 768 const RuntimeEntry& handle_ic_miss) { | 768 const RuntimeEntry& handle_ic_miss) { |
| 769 ASSERT(num_args > 0); | 769 ASSERT(num_args > 0); |
| 770 #if defined(DEBUG) | 770 #if defined(DEBUG) |
| 771 { Label ok; | 771 { Label ok; |
| 772 // Check that the IC data array has NumArgsTested() == num_args. | 772 // Check that the IC data array has NumArgsTested() == num_args. |
| 773 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 773 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 774 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 774 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 775 kUnsignedWord); | 775 kUnsignedWord); |
| 776 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 776 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 777 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 777 __ andi(R6, R6, ICData::NumArgsTestedMask()); |
| 778 __ CompareImmediate(R6, num_args, PP); | 778 __ CompareImmediate(R6, num_args, kNoRegister); |
| 779 __ b(&ok, EQ); | 779 __ b(&ok, EQ); |
| 780 __ Stop("Incorrect stub for IC data"); | 780 __ Stop("Incorrect stub for IC data"); |
| 781 __ Bind(&ok); | 781 __ Bind(&ok); |
| 782 } | 782 } |
| 783 #endif // DEBUG | 783 #endif // DEBUG |
| 784 | 784 |
| 785 // Check single stepping. | 785 // Check single stepping. |
| 786 Label not_stepping; | 786 Label not_stepping; |
| 787 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); | 787 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); |
| 788 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); | 788 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); |
| 789 __ CompareImmediate(R6, 0, PP); | 789 __ CompareImmediate(R6, 0, kNoRegister); |
| 790 __ b(¬_stepping, EQ); | 790 __ b(¬_stepping, EQ); |
| 791 __ EnterStubFrame(); | 791 __ EnterStubFrame(); |
| 792 __ Push(R5); // Preserve IC data. | 792 __ Push(R5); // Preserve IC data. |
| 793 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 793 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 794 __ Pop(R5); | 794 __ Pop(R5); |
| 795 __ LeaveStubFrame(); | 795 __ LeaveStubFrame(); |
| 796 __ Bind(¬_stepping); | 796 __ Bind(¬_stepping); |
| 797 | 797 |
| 798 // Load arguments descriptor into R4. | 798 // Load arguments descriptor into R4. |
| 799 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 799 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| 800 // Loop that checks if there is an IC data match. | 800 // Loop that checks if there is an IC data match. |
| 801 Label loop, update, test, found, get_class_id_as_smi; | 801 Label loop, update, test, found, get_class_id_as_smi; |
| 802 // R5: IC data object (preserved). | 802 // R5: IC data object (preserved). |
| 803 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); | 803 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); |
| 804 // R6: ic_data_array with check entries: classes and target functions. | 804 // R6: ic_data_array with check entries: classes and target functions. |
| 805 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, PP); | 805 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoRegister); |
| 806 // R6: points directly to the first ic data array element. | 806 // R6: points directly to the first ic data array element. |
| 807 | 807 |
| 808 // Get the receiver's class ID (first read number of arguments from | 808 // Get the receiver's class ID (first read number of arguments from |
| 809 // arguments descriptor array and then access the receiver from the stack). | 809 // arguments descriptor array and then access the receiver from the stack). |
| 810 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 810 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
| 811 __ SmiUntag(R7); // Untag so we can use the LSL 3 addressing mode. | 811 __ SmiUntag(R7); // Untag so we can use the LSL 3 addressing mode. |
| 812 __ sub(R7, R7, Operand(1)); | 812 __ sub(R7, R7, Operand(1)); |
| 813 | 813 |
| 814 // R0 <- [SP + (R7 << 3)] | 814 // R0 <- [SP + (R7 << 3)] |
| 815 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); | 815 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); |
| 816 | 816 |
| 817 { | 817 { |
| 818 // TODO(zra): Put this code in a subroutine call as with other architectures | 818 // TODO(zra): Put this code in a subroutine call as with other architectures |
| 819 // when we have a bl(Label& l) instruction. | 819 // when we have a bl(Label& l) instruction. |
| 820 // Instance in R0, return its class-id in R0 as Smi. | 820 // Instance in R0, return its class-id in R0 as Smi. |
| 821 // Test if Smi -> load Smi class for comparison. | 821 // Test if Smi -> load Smi class for comparison. |
| 822 Label not_smi, done; | 822 Label not_smi, done; |
| 823 __ tsti(R0, kSmiTagMask); | 823 __ tsti(R0, kSmiTagMask); |
| 824 __ b(¬_smi, NE); | 824 __ b(¬_smi, NE); |
| 825 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), PP); | 825 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), kNoRegister); |
| 826 __ b(&done); | 826 __ b(&done); |
| 827 | 827 |
| 828 __ Bind(¬_smi); | 828 __ Bind(¬_smi); |
| 829 __ LoadClassId(R0, R0); | 829 __ LoadClassId(R0, R0); |
| 830 __ SmiTag(R0); | 830 __ SmiTag(R0); |
| 831 __ Bind(&done); | 831 __ Bind(&done); |
| 832 } | 832 } |
| 833 | 833 |
| 834 // R7: argument_count - 1 (untagged). | 834 // R7: argument_count - 1 (untagged). |
| 835 // R0: receiver's class ID (smi). | 835 // R0: receiver's class ID (smi). |
| 836 __ ldr(R1, Address(R6)); // First class id (smi) to check. | 836 __ ldr(R1, Address(R6)); // First class id (smi) to check. |
| 837 __ b(&test); | 837 __ b(&test); |
| 838 | 838 |
| 839 __ Bind(&loop); | 839 __ Bind(&loop); |
| 840 for (int i = 0; i < num_args; i++) { | 840 for (int i = 0; i < num_args; i++) { |
| 841 if (i > 0) { | 841 if (i > 0) { |
| 842 // If not the first, load the next argument's class ID. | 842 // If not the first, load the next argument's class ID. |
| 843 __ AddImmediate(R0, R7, -i, PP); | 843 __ AddImmediate(R0, R7, -i, kNoRegister); |
| 844 // R0 <- [SP + (R0 << 3)] | 844 // R0 <- [SP + (R0 << 3)] |
| 845 __ ldr(R0, Address(SP, R0, UXTX, Address::Scaled)); | 845 __ ldr(R0, Address(SP, R0, UXTX, Address::Scaled)); |
| 846 { | 846 { |
| 847 // Instance in R0, return its class-id in R0 as Smi. | 847 // Instance in R0, return its class-id in R0 as Smi. |
| 848 // Test if Smi -> load Smi class for comparison. | 848 // Test if Smi -> load Smi class for comparison. |
| 849 Label not_smi, done; | 849 Label not_smi, done; |
| 850 __ tsti(R0, kSmiTagMask); | 850 __ tsti(R0, kSmiTagMask); |
| 851 __ b(¬_smi, NE); | 851 __ b(¬_smi, NE); |
| 852 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), PP); | 852 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), kNoRegister); |
| 853 __ b(&done); | 853 __ b(&done); |
| 854 | 854 |
| 855 __ Bind(¬_smi); | 855 __ Bind(¬_smi); |
| 856 __ LoadClassId(R0, R0); | 856 __ LoadClassId(R0, R0); |
| 857 __ SmiTag(R0); | 857 __ SmiTag(R0); |
| 858 __ Bind(&done); | 858 __ Bind(&done); |
| 859 } | 859 } |
| 860 // R0: next argument class ID (smi). | 860 // R0: next argument class ID (smi). |
| 861 __ LoadFromOffset(R1, R6, i * kWordSize); | 861 __ LoadFromOffset(R1, R6, i * kWordSize); |
| 862 // R1: next class ID to check (smi). | 862 // R1: next class ID to check (smi). |
| 863 } | 863 } |
| 864 __ CompareRegisters(R0, R1); // Class id match? | 864 __ CompareRegisters(R0, R1); // Class id match? |
| 865 if (i < (num_args - 1)) { | 865 if (i < (num_args - 1)) { |
| 866 __ b(&update, NE); // Continue. | 866 __ b(&update, NE); // Continue. |
| 867 } else { | 867 } else { |
| 868 // Last check, all checks before matched. | 868 // Last check, all checks before matched. |
| 869 __ b(&found, EQ); // Break. | 869 __ b(&found, EQ); // Break. |
| 870 } | 870 } |
| 871 } | 871 } |
| 872 __ Bind(&update); | 872 __ Bind(&update); |
| 873 // Reload receiver class ID. It has not been destroyed when num_args == 1. | 873 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 874 if (num_args > 1) { | 874 if (num_args > 1) { |
| 875 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); | 875 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); |
| 876 { | 876 { |
| 877 // Instance in R0, return its class-id in R0 as Smi. | 877 // Instance in R0, return its class-id in R0 as Smi. |
| 878 // Test if Smi -> load Smi class for comparison. | 878 // Test if Smi -> load Smi class for comparison. |
| 879 Label not_smi, done; | 879 Label not_smi, done; |
| 880 __ tsti(R0, kSmiTagMask); | 880 __ tsti(R0, kSmiTagMask); |
| 881 __ b(¬_smi, NE); | 881 __ b(¬_smi, NE); |
| 882 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), PP); | 882 __ LoadImmediate(R0, Smi::RawValue(kSmiCid), kNoRegister); |
| 883 __ b(&done); | 883 __ b(&done); |
| 884 | 884 |
| 885 __ Bind(¬_smi); | 885 __ Bind(¬_smi); |
| 886 __ LoadClassId(R0, R0); | 886 __ LoadClassId(R0, R0); |
| 887 __ SmiTag(R0); | 887 __ SmiTag(R0); |
| 888 __ Bind(&done); | 888 __ Bind(&done); |
| 889 } | 889 } |
| 890 } | 890 } |
| 891 | 891 |
| 892 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; | 892 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 893 __ AddImmediate(R6, R6, entry_size, PP); // Next entry. | 893 __ AddImmediate(R6, R6, entry_size, kNoRegister); // Next entry. |
| 894 __ ldr(R1, Address(R6)); // Next class ID. | 894 __ ldr(R1, Address(R6)); // Next class ID. |
| 895 | 895 |
| 896 __ Bind(&test); | 896 __ Bind(&test); |
| 897 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid), PP); // Done? | 897 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid), kNoRegister); // Done? |
| 898 __ b(&loop, NE); | 898 __ b(&loop, NE); |
| 899 | 899 |
| 900 // IC miss. | 900 // IC miss. |
| 901 // Compute address of arguments. | 901 // Compute address of arguments. |
| 902 // R7: argument_count - 1 (untagged). | 902 // R7: argument_count - 1 (untagged). |
| 903 // R7 <- SP + (R7 << 3) | 903 // R7 <- SP + (R7 << 3) |
| 904 __ add(R7, SP, Operand(R7, UXTX, 3)); // R7 is Untagged. | 904 __ add(R7, SP, Operand(R7, UXTX, 3)); // R7 is Untagged. |
| 905 // R7: address of receiver. | 905 // R7: address of receiver. |
| 906 // Create a stub frame as we are pushing some objects on the stack before | 906 // Create a stub frame as we are pushing some objects on the stack before |
| 907 // calling into the runtime. | 907 // calling into the runtime. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 933 | 933 |
| 934 __ Bind(&found); | 934 __ Bind(&found); |
| 935 // R6: pointer to an IC data check group. | 935 // R6: pointer to an IC data check group. |
| 936 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 936 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 937 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 937 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 938 __ LoadFromOffset(R0, R6, target_offset); | 938 __ LoadFromOffset(R0, R6, target_offset); |
| 939 __ LoadFromOffset(R1, R6, count_offset); | 939 __ LoadFromOffset(R1, R6, count_offset); |
| 940 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 940 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 941 __ StoreToOffset(R1, R6, count_offset); | 941 __ StoreToOffset(R1, R6, count_offset); |
| 942 __ b(&call_target_function, VC); // No overflow. | 942 __ b(&call_target_function, VC); // No overflow. |
| 943 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), PP); | 943 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), kNoRegister); |
| 944 __ StoreToOffset(R1, R6, count_offset); | 944 __ StoreToOffset(R1, R6, count_offset); |
| 945 | 945 |
| 946 __ Bind(&call_target_function); | 946 __ Bind(&call_target_function); |
| 947 // R0: target function. | 947 // R0: target function. |
| 948 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); | 948 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); |
| 949 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); | 949 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); |
| 950 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); | 950 __ AddImmediate( |
| 951 R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoRegister); |
| 951 __ br(R2); | 952 __ br(R2); |
| 952 } | 953 } |
| 953 | 954 |
| 954 | 955 |
| 955 // Use inline cache data array to invoke the target or continue in inline | 956 // Use inline cache data array to invoke the target or continue in inline |
| 956 // cache miss handler. Stub for 1-argument check (receiver class). | 957 // cache miss handler. Stub for 1-argument check (receiver class). |
| 957 // LR: return address. | 958 // LR: return address. |
| 958 // R5: inline cache data object. | 959 // R5: inline cache data object. |
| 959 // Inline cache data object structure: | 960 // Inline cache data object structure: |
| 960 // 0: function-name | 961 // 0: function-name |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1013 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1013 GenerateUsageCounterIncrement(assembler, R6); | 1014 GenerateUsageCounterIncrement(assembler, R6); |
| 1014 #if defined(DEBUG) | 1015 #if defined(DEBUG) |
| 1015 { Label ok; | 1016 { Label ok; |
| 1016 // Check that the IC data array has NumArgsTested() == 0. | 1017 // Check that the IC data array has NumArgsTested() == 0. |
| 1017 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1018 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1018 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1019 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1019 kUnsignedWord); | 1020 kUnsignedWord); |
| 1020 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1021 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1021 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 1022 __ andi(R6, R6, ICData::NumArgsTestedMask()); |
| 1022 __ CompareImmediate(R6, 0, PP); | 1023 __ CompareImmediate(R6, 0, kNoRegister); |
| 1023 __ b(&ok, EQ); | 1024 __ b(&ok, EQ); |
| 1024 __ Stop("Incorrect IC data for unoptimized static call"); | 1025 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1025 __ Bind(&ok); | 1026 __ Bind(&ok); |
| 1026 } | 1027 } |
| 1027 #endif // DEBUG | 1028 #endif // DEBUG |
| 1028 | 1029 |
| 1029 // Check single stepping. | 1030 // Check single stepping. |
| 1030 Label not_stepping; | 1031 Label not_stepping; |
| 1031 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); | 1032 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); |
| 1032 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); | 1033 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); |
| 1033 __ CompareImmediate(R6, 0, PP); | 1034 __ CompareImmediate(R6, 0, kNoRegister); |
| 1034 __ b(¬_stepping, EQ); | 1035 __ b(¬_stepping, EQ); |
| 1035 __ EnterStubFrame(); | 1036 __ EnterStubFrame(); |
| 1036 __ Push(R5); // Preserve IC data. | 1037 __ Push(R5); // Preserve IC data. |
| 1037 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1038 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1038 __ Pop(R5); | 1039 __ Pop(R5); |
| 1039 __ LeaveStubFrame(); | 1040 __ LeaveStubFrame(); |
| 1040 __ Bind(¬_stepping); | 1041 __ Bind(¬_stepping); |
| 1041 | 1042 |
| 1042 // R5: IC data object (preserved). | 1043 // R5: IC data object (preserved). |
| 1043 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); | 1044 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); |
| 1044 // R6: ic_data_array with entries: target functions and count. | 1045 // R6: ic_data_array with entries: target functions and count. |
| 1045 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, PP); | 1046 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoRegister); |
| 1046 // R6: points directly to the first ic data array element. | 1047 // R6: points directly to the first ic data array element. |
| 1047 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1048 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
| 1048 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1049 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
| 1049 | 1050 |
| 1050 // Increment count for this call. | 1051 // Increment count for this call. |
| 1051 Label increment_done; | 1052 Label increment_done; |
| 1052 __ LoadFromOffset(R1, R6, count_offset); | 1053 __ LoadFromOffset(R1, R6, count_offset); |
| 1053 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1054 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1054 __ StoreToOffset(R1, R6, count_offset); | 1055 __ StoreToOffset(R1, R6, count_offset); |
| 1055 __ b(&increment_done, VC); // No overflow. | 1056 __ b(&increment_done, VC); // No overflow. |
| 1056 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), PP); | 1057 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), kNoRegister); |
| 1057 __ StoreToOffset(R1, R6, count_offset); | 1058 __ StoreToOffset(R1, R6, count_offset); |
| 1058 __ Bind(&increment_done); | 1059 __ Bind(&increment_done); |
| 1059 | 1060 |
| 1060 // Load arguments descriptor into R4. | 1061 // Load arguments descriptor into R4. |
| 1061 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 1062 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| 1062 | 1063 |
| 1063 // Get function and call it, if possible. | 1064 // Get function and call it, if possible. |
| 1064 __ LoadFromOffset(R0, R6, target_offset); | 1065 __ LoadFromOffset(R0, R6, target_offset); |
| 1065 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); | 1066 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); |
| 1066 | 1067 |
| 1067 // R0: function. | 1068 // R0: function. |
| 1068 // R2: target code. | 1069 // R2: target code. |
| 1069 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); | 1070 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); |
| 1070 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); | 1071 __ AddImmediate( |
| 1072 R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoRegister); |
| 1071 __ br(R2); | 1073 __ br(R2); |
| 1072 } | 1074 } |
| 1073 | 1075 |
| 1074 | 1076 |
| 1075 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1077 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1076 __ Stop("GenerateTwoArgsUnoptimizedStaticCallStub"); | 1078 __ Stop("GenerateTwoArgsUnoptimizedStaticCallStub"); |
| 1077 } | 1079 } |
| 1078 | 1080 |
| 1079 | 1081 |
| 1080 // Stub for compiling a function and jumping to the compiled code. | 1082 // Stub for compiling a function and jumping to the compiled code. |
| 1081 // R5: IC-Data (for methods). | 1083 // R5: IC-Data (for methods). |
| 1082 // R4: Arguments descriptor. | 1084 // R4: Arguments descriptor. |
| 1083 // R0: Function. | 1085 // R0: Function. |
| 1084 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1086 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1085 // Preserve arg desc. and IC data object. | 1087 // Preserve arg desc. and IC data object. |
| 1086 __ EnterStubFrame(); | 1088 __ EnterStubFrame(); |
| 1087 __ Push(R5); // Save IC Data. | 1089 __ Push(R5); // Save IC Data. |
| 1088 __ Push(R4); // Save arg. desc. | 1090 __ Push(R4); // Save arg. desc. |
| 1089 __ Push(R0); // Pass function. | 1091 __ Push(R0); // Pass function. |
| 1090 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1092 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1091 __ Pop(R0); // Restore argument. | 1093 __ Pop(R0); // Restore argument. |
| 1092 __ Pop(R4); // Restore arg desc. | 1094 __ Pop(R4); // Restore arg desc. |
| 1093 __ Pop(R5); // Restore IC Data. | 1095 __ Pop(R5); // Restore IC Data. |
| 1094 __ LeaveStubFrame(); | 1096 __ LeaveStubFrame(); |
| 1095 | 1097 |
| 1096 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); | 1098 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); |
| 1097 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); | 1099 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); |
| 1098 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); | 1100 __ AddImmediate( |
| 1101 R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoRegister); |
| 1099 __ br(R2); | 1102 __ br(R2); |
| 1100 } | 1103 } |
| 1101 | 1104 |
| 1102 | 1105 |
| 1103 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { | 1106 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { |
| 1104 __ Stop("GenerateBreakpointRuntimeStub"); | 1107 __ Stop("GenerateBreakpointRuntimeStub"); |
| 1105 } | 1108 } |
| 1106 | 1109 |
| 1107 | 1110 |
| 1108 // Called only from unoptimized code. All relevant registers have been saved. | 1111 // Called only from unoptimized code. All relevant registers have been saved. |
| 1109 void StubCode::GenerateDebugStepCheckStub( | 1112 void StubCode::GenerateDebugStepCheckStub( |
| 1110 Assembler* assembler) { | 1113 Assembler* assembler) { |
| 1111 // Check single stepping. | 1114 // Check single stepping. |
| 1112 Label not_stepping; | 1115 Label not_stepping; |
| 1113 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); | 1116 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); |
| 1114 __ LoadFromOffset(R1, R1, Isolate::single_step_offset(), kUnsignedByte); | 1117 __ LoadFromOffset(R1, R1, Isolate::single_step_offset(), kUnsignedByte); |
| 1115 __ CompareImmediate(R1, 0, PP); | 1118 __ CompareImmediate(R1, 0, kNoRegister); |
| 1116 __ b(¬_stepping, EQ); | 1119 __ b(¬_stepping, EQ); |
| 1117 __ EnterStubFrame(); | 1120 __ EnterStubFrame(); |
| 1118 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1121 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1119 __ LeaveStubFrame(); | 1122 __ LeaveStubFrame(); |
| 1120 __ Bind(¬_stepping); | 1123 __ Bind(¬_stepping); |
| 1121 __ ret(); | 1124 __ ret(); |
| 1122 } | 1125 } |
| 1123 | 1126 |
| 1124 | 1127 |
| 1125 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) { | 1128 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1222 // LR: return address. | 1225 // LR: return address. |
| 1223 // SP + 4: left operand. | 1226 // SP + 4: left operand. |
| 1224 // SP + 0: right operand. | 1227 // SP + 0: right operand. |
| 1225 // Return Zero condition flag set if equal. | 1228 // Return Zero condition flag set if equal. |
| 1226 void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub( | 1229 void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub( |
| 1227 Assembler* assembler) { | 1230 Assembler* assembler) { |
| 1228 // Check single stepping. | 1231 // Check single stepping. |
| 1229 Label not_stepping; | 1232 Label not_stepping; |
| 1230 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); | 1233 __ LoadFieldFromOffset(R1, CTX, Context::isolate_offset()); |
| 1231 __ LoadFromOffset(R1, R1, Isolate::single_step_offset(), kUnsignedByte); | 1234 __ LoadFromOffset(R1, R1, Isolate::single_step_offset(), kUnsignedByte); |
| 1232 __ CompareImmediate(R1, 0, PP); | 1235 __ CompareImmediate(R1, 0, kNoRegister); |
| 1233 __ b(¬_stepping, EQ); | 1236 __ b(¬_stepping, EQ); |
| 1234 __ EnterStubFrame(); | 1237 __ EnterStubFrame(); |
| 1235 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1238 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1236 __ LeaveStubFrame(); | 1239 __ LeaveStubFrame(); |
| 1237 __ Bind(¬_stepping); | 1240 __ Bind(¬_stepping); |
| 1238 | 1241 |
| 1239 const Register left = R1; | 1242 const Register left = R1; |
| 1240 const Register right = R0; | 1243 const Register right = R0; |
| 1241 __ LoadFromOffset(left, SP, 1 * kWordSize); | 1244 __ LoadFromOffset(left, SP, 1 * kWordSize); |
| 1242 __ LoadFromOffset(right, SP, 0 * kWordSize); | 1245 __ LoadFromOffset(right, SP, 0 * kWordSize); |
| 1243 GenerateIdenticalWithNumberCheckStub(assembler, left, right); | 1246 GenerateIdenticalWithNumberCheckStub(assembler, left, right); |
| 1244 __ ret(); | 1247 __ ret(); |
| 1245 } | 1248 } |
| 1246 | 1249 |
| 1247 | 1250 |
| 1248 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( | 1251 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( |
| 1249 Assembler* assembler) { | 1252 Assembler* assembler) { |
| 1250 __ Stop("GenerateOptimizedIdenticalWithNumberCheckStub"); | 1253 __ Stop("GenerateOptimizedIdenticalWithNumberCheckStub"); |
| 1251 } | 1254 } |
| 1252 | 1255 |
| 1253 } // namespace dart | 1256 } // namespace dart |
| 1254 | 1257 |
| 1255 #endif // defined TARGET_ARCH_ARM64 | 1258 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |