| 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 23 matching lines...) Expand all Loading... |
| 34 // SP : address of last argument in argument array. | 34 // SP : address of last argument in argument array. |
| 35 // SP + 8*R4 - 8 : address of first argument in argument array. | 35 // SP + 8*R4 - 8 : address of first argument in argument array. |
| 36 // SP + 8*R4 : address of return value. | 36 // SP + 8*R4 : address of return value. |
| 37 // R5 : address of the runtime function to call. | 37 // R5 : address of the runtime function to call. |
| 38 // R4 : number of arguments to the call. | 38 // R4 : number of arguments to the call. |
| 39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 40 const intptr_t thread_offset = NativeArguments::thread_offset(); | 40 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 41 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 41 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 42 const intptr_t argv_offset = NativeArguments::argv_offset(); | 42 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 43 const intptr_t retval_offset = NativeArguments::retval_offset(); | 43 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 44 const intptr_t exitframe_last_param_slot_from_fp = 1; |
| 44 | 45 |
| 45 __ SetPrologueOffset(); | 46 __ SetPrologueOffset(); |
| 46 __ Comment("CallToRuntimeStub"); | 47 __ Comment("CallToRuntimeStub"); |
| 47 __ EnterStubFrame(); | 48 __ EnterStubFrame(); |
| 48 | 49 |
| 49 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0); | 50 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0); |
| 50 __ LoadIsolate(R28); | 51 __ LoadIsolate(R28); |
| 51 | 52 |
| 52 // Save exit frame information to enable stack walking as we are about | 53 // Save exit frame information to enable stack walking as we are about |
| 53 // to transition to Dart VM C++ code. | 54 // to transition to Dart VM C++ code. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 83 | 84 |
| 84 // There are no runtime calls to closures, so we do not need to set the tag | 85 // There are no runtime calls to closures, so we do not need to set the tag |
| 85 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 86 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 86 ASSERT(argc_tag_offset == 1 * kWordSize); | 87 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 87 __ mov(R1, R4); // Set argc in NativeArguments. | 88 __ mov(R1, R4); // Set argc in NativeArguments. |
| 88 | 89 |
| 89 ASSERT(argv_offset == 2 * kWordSize); | 90 ASSERT(argv_offset == 2 * kWordSize); |
| 90 __ add(R2, ZR, Operand(R4, LSL, 3)); | 91 __ add(R2, ZR, Operand(R4, LSL, 3)); |
| 91 __ add(R2, FP, Operand(R2)); // Compute argv. | 92 __ add(R2, FP, Operand(R2)); // Compute argv. |
| 92 // Set argv in NativeArguments. | 93 // Set argv in NativeArguments. |
| 93 __ AddImmediate(R2, R2, kParamEndSlotFromFp * kWordSize); | 94 __ AddImmediate(R2, R2, exitframe_last_param_slot_from_fp * kWordSize); |
| 94 | 95 |
| 95 ASSERT(retval_offset == 3 * kWordSize); | 96 ASSERT(retval_offset == 3 * kWordSize); |
| 96 __ AddImmediate(R3, R2, kWordSize); | 97 __ AddImmediate(R3, R2, kWordSize); |
| 97 | 98 |
| 98 __ StoreToOffset(R0, SP, thread_offset); | 99 __ StoreToOffset(R0, SP, thread_offset); |
| 99 __ StoreToOffset(R1, SP, argc_tag_offset); | 100 __ StoreToOffset(R1, SP, argc_tag_offset); |
| 100 __ StoreToOffset(R2, SP, argv_offset); | 101 __ StoreToOffset(R2, SP, argv_offset); |
| 101 __ StoreToOffset(R3, SP, retval_offset); | 102 __ StoreToOffset(R3, SP, retval_offset); |
| 102 __ mov(R0, SP); // Pass the pointer to the NativeArguments. | 103 __ mov(R0, SP); // Pass the pointer to the NativeArguments. |
| 103 | 104 |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 // R4: arguments descriptor array. | 339 // R4: arguments descriptor array. |
| 339 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 340 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 340 // Create a stub frame as we are pushing some objects on the stack before | 341 // Create a stub frame as we are pushing some objects on the stack before |
| 341 // calling into the runtime. | 342 // calling into the runtime. |
| 342 __ EnterStubFrame(); | 343 __ EnterStubFrame(); |
| 343 // Setup space on stack for return value and preserve arguments descriptor. | 344 // Setup space on stack for return value and preserve arguments descriptor. |
| 344 __ Push(R4); | 345 __ Push(R4); |
| 345 __ PushObject(Object::null_object()); | 346 __ PushObject(Object::null_object()); |
| 346 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); | 347 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
| 347 // Get Code object result and restore arguments descriptor array. | 348 // Get Code object result and restore arguments descriptor array. |
| 348 __ Pop(CODE_REG); | 349 __ Pop(R0); |
| 349 __ Pop(R4); | 350 __ Pop(R4); |
| 350 // Remove the stub frame. | 351 // Remove the stub frame. |
| 351 __ LeaveStubFrame(); | 352 __ LeaveStubFrame(); |
| 352 // Jump to the dart function. | 353 // Jump to the dart function. |
| 353 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | 354 __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
| 354 __ br(R0); | 355 __ br(R0); |
| 355 } | 356 } |
| 356 | 357 |
| 357 | 358 |
| 358 // Called from a static call only when an invalid code has been entered | 359 // Called from a static call only when an invalid code has been entered |
| 359 // (invalid because its function was optimized or deoptimized). | 360 // (invalid because its function was optimized or deoptimized). |
| 360 // R4: arguments descriptor array. | 361 // R4: arguments descriptor array. |
| 361 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 362 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 362 // Load code pointer to this stub from the thread: | |
| 363 // The one that is passed in, is not correct - it points to the code object | |
| 364 // that needs to be replaced. | |
| 365 __ ldr(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); | |
| 366 // Create a stub frame as we are pushing some objects on the stack before | 363 // Create a stub frame as we are pushing some objects on the stack before |
| 367 // calling into the runtime. | 364 // calling into the runtime. |
| 368 __ EnterStubFrame(); | 365 __ EnterStubFrame(); |
| 369 // Setup space on stack for return value and preserve arguments descriptor. | 366 // Setup space on stack for return value and preserve arguments descriptor. |
| 370 __ Push(R4); | 367 __ Push(R4); |
| 371 __ PushObject(Object::null_object()); | 368 __ PushObject(Object::null_object()); |
| 372 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); | 369 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
| 373 // Get Code object result and restore arguments descriptor array. | 370 // Get Code object result and restore arguments descriptor array. |
| 374 __ Pop(CODE_REG); | 371 __ Pop(R0); |
| 375 __ Pop(R4); | 372 __ Pop(R4); |
| 376 // Remove the stub frame. | 373 // Remove the stub frame. |
| 377 __ LeaveStubFrame(); | 374 __ LeaveStubFrame(); |
| 378 // Jump to the dart function. | 375 // Jump to the dart function. |
| 379 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | 376 __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
| 380 __ br(R0); | 377 __ br(R0); |
| 381 } | 378 } |
| 382 | 379 |
| 383 | 380 |
| 384 // Called from object allocate instruction when the allocation stub has been | 381 // Called from object allocate instruction when the allocation stub has been |
| 385 // disabled. | 382 // disabled. |
| 386 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { | 383 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { |
| 387 // Load code pointer to this stub from the thread: | |
| 388 // The one that is passed in, is not correct - it points to the code object | |
| 389 // that needs to be replaced. | |
| 390 __ ldr(CODE_REG, Address(THR, Thread::fix_allocation_stub_code_offset())); | |
| 391 __ EnterStubFrame(); | 384 __ EnterStubFrame(); |
| 392 // Setup space on stack for return value. | 385 // Setup space on stack for return value. |
| 393 __ PushObject(Object::null_object()); | 386 __ PushObject(Object::null_object()); |
| 394 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); | 387 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); |
| 395 // Get Code object result. | 388 // Get Code object result. |
| 396 __ Pop(CODE_REG); | 389 __ Pop(R0); |
| 397 // Remove the stub frame. | 390 // Remove the stub frame. |
| 398 __ LeaveStubFrame(); | 391 __ LeaveStubFrame(); |
| 399 // Jump to the dart function. | 392 // Jump to the dart function. |
| 400 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | 393 __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
| 401 __ br(R0); | 394 __ br(R0); |
| 402 } | 395 } |
| 403 | 396 |
| 404 | 397 |
| 405 // Input parameters: | 398 // Input parameters: |
| 406 // R2: smi-tagged argument count, may be zero. | 399 // R2: smi-tagged argument count, may be zero. |
| 407 // FP[kParamEndSlotFromFp + 1]: last argument. | 400 // FP[kParamEndSlotFromFp + 1]: last argument. |
| 408 static void PushArgumentsArray(Assembler* assembler) { | 401 static void PushArgumentsArray(Assembler* assembler) { |
| 409 // Allocate array to store arguments of caller. | 402 // Allocate array to store arguments of caller. |
| 410 __ LoadObject(R1, Object::null_object()); | 403 __ LoadObject(R1, Object::null_object()); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 // Stack after TagAndPushPP() below: | 441 // Stack after TagAndPushPP() below: |
| 449 // +------------------+ | 442 // +------------------+ |
| 450 // | Saved PP | <- PP | 443 // | Saved PP | <- PP |
| 451 // +------------------+ | 444 // +------------------+ |
| 452 // | PC marker | <- TOS | 445 // | PC marker | <- TOS |
| 453 // +------------------+ | 446 // +------------------+ |
| 454 // | Saved FP | <- FP of stub | 447 // | Saved FP | <- FP of stub |
| 455 // +------------------+ | 448 // +------------------+ |
| 456 // | return-address | (deoptimization point) | 449 // | return-address | (deoptimization point) |
| 457 // +------------------+ | 450 // +------------------+ |
| 458 // | Saved CODE_REG | | |
| 459 // +------------------+ | |
| 460 // | ... | <- SP of optimized frame | 451 // | ... | <- SP of optimized frame |
| 461 // | 452 // |
| 462 // Parts of the code cannot GC, part of the code can GC. | 453 // Parts of the code cannot GC, part of the code can GC. |
| 463 static void GenerateDeoptimizationSequence(Assembler* assembler, | 454 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 464 DeoptStubKind kind) { | 455 bool preserve_result) { |
| 465 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 456 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 466 // is no need to set the correct PC marker or load PP, since they get patched. | 457 // is no need to set the correct PC marker or load PP, since they get patched. |
| 467 __ EnterStubFrame(); | 458 __ EnterStubFrame(); |
| 468 | 459 |
| 469 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry | 460 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 470 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. | 461 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 471 const intptr_t saved_result_slot_from_fp = | 462 const intptr_t saved_result_slot_from_fp = |
| 472 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - R0); | 463 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - R0); |
| 473 // Result in R0 is preserved as part of pushing all registers below. | 464 // Result in R0 is preserved as part of pushing all registers below. |
| 474 | 465 |
| 475 // Push registers in their enumeration order: lowest register number at | 466 // Push registers in their enumeration order: lowest register number at |
| 476 // lowest address. | 467 // lowest address. |
| 477 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { | 468 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
| 478 const Register r = static_cast<Register>(i); | 469 const Register r = static_cast<Register>(i); |
| 479 if (r == CODE_REG) { | 470 __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); |
| 480 // Save the original value of CODE_REG pushed before invoking this stub | |
| 481 // instead of the value used to call this stub. | |
| 482 COMPILE_ASSERT(R25 > CODE_REG); | |
| 483 __ ldr(R25, Address(FP, 2 * kWordSize)); | |
| 484 __ str(R25, Address(SP, -1 * kWordSize, Address::PreIndex)); | |
| 485 } else { | |
| 486 __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); | |
| 487 } | |
| 488 } | 471 } |
| 489 | 472 |
| 490 for (intptr_t reg_idx = kNumberOfVRegisters - 1; reg_idx >= 0; reg_idx--) { | 473 for (intptr_t reg_idx = kNumberOfVRegisters - 1; reg_idx >= 0; reg_idx--) { |
| 491 VRegister vreg = static_cast<VRegister>(reg_idx); | 474 VRegister vreg = static_cast<VRegister>(reg_idx); |
| 492 __ PushQuad(vreg); | 475 __ PushQuad(vreg); |
| 493 } | 476 } |
| 494 | 477 |
| 495 __ mov(R0, SP); // Pass address of saved registers block. | 478 __ mov(R0, SP); // Pass address of saved registers block. |
| 496 __ LoadImmediate(R1, kind == kLazyDeopt ? 1 : 0); | |
| 497 __ ReserveAlignedFrameSpace(0); | 479 __ ReserveAlignedFrameSpace(0); |
| 498 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); | 480 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 1); |
| 499 // Result (R0) is stack-size (FP - SP) in bytes. | 481 // Result (R0) is stack-size (FP - SP) in bytes. |
| 500 | 482 |
| 501 const bool preserve_result = (kind == kLazyDeopt); | |
| 502 if (preserve_result) { | 483 if (preserve_result) { |
| 503 // Restore result into R1 temporarily. | 484 // Restore result into R1 temporarily. |
| 504 __ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize); | 485 __ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize); |
| 505 } | 486 } |
| 506 | 487 |
| 507 // There is a Dart Frame on the stack. We must restore PP and leave frame. | 488 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 508 __ RestoreCodePointer(); | |
| 509 __ LeaveStubFrame(); | 489 __ LeaveStubFrame(); |
| 510 __ sub(SP, FP, Operand(R0)); | 490 __ sub(SP, FP, Operand(R0)); |
| 511 | 491 |
| 512 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 492 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 513 // is no need to set the correct PC marker or load PP, since they get patched. | 493 // is no need to set the correct PC marker or load PP, since they get patched. |
| 514 __ EnterStubFrame(); | 494 __ EnterStubFrame(); |
| 515 | 495 |
| 516 if (preserve_result) { | 496 if (preserve_result) { |
| 517 __ Push(R1); // Preserve result as first local. | 497 __ Push(R1); // Preserve result as first local. |
| 518 } | 498 } |
| 519 __ ReserveAlignedFrameSpace(0); | 499 __ ReserveAlignedFrameSpace(0); |
| 520 __ mov(R0, FP); // Pass last FP as parameter in R0. | 500 __ mov(R0, FP); // Pass last FP as parameter in R0. |
| 521 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); | 501 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); |
| 522 if (preserve_result) { | 502 if (preserve_result) { |
| 523 // Restore result into R1. | 503 // Restore result into R1. |
| 524 __ LoadFromOffset(R1, FP, kFirstLocalSlotFromFp * kWordSize); | 504 __ LoadFromOffset(R1, FP, kFirstLocalSlotFromFp * kWordSize); |
| 525 } | 505 } |
| 526 // Code above cannot cause GC. | 506 // Code above cannot cause GC. |
| 527 // There is a Dart Frame on the stack. We must restore PP and leave frame. | 507 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 528 __ RestoreCodePointer(); | |
| 529 __ LeaveStubFrame(); | 508 __ LeaveStubFrame(); |
| 530 | 509 |
| 531 // Frame is fully rewritten at this point and it is safe to perform a GC. | 510 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 532 // Materialize any objects that were deferred by FillFrame because they | 511 // Materialize any objects that were deferred by FillFrame because they |
| 533 // require allocation. | 512 // require allocation. |
| 534 // Enter stub frame with loading PP. The caller's PP is not materialized yet. | 513 // Enter stub frame with loading PP. The caller's PP is not materialized yet. |
| 535 __ EnterStubFrame(); | 514 __ EnterStubFrame(); |
| 536 if (preserve_result) { | 515 if (preserve_result) { |
| 537 __ Push(R1); // Preserve result, it will be GC-d here. | 516 __ Push(R1); // Preserve result, it will be GC-d here. |
| 538 } | 517 } |
| 539 __ Push(ZR); // Space for the result. | 518 __ Push(ZR); // Space for the result. |
| 540 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); | 519 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); |
| 541 // Result tells stub how many bytes to remove from the expression stack | 520 // Result tells stub how many bytes to remove from the expression stack |
| 542 // of the bottom-most frame. They were used as materialization arguments. | 521 // of the bottom-most frame. They were used as materialization arguments. |
| 543 __ Pop(R1); | 522 __ Pop(R1); |
| 544 __ SmiUntag(R1); | 523 __ SmiUntag(R1); |
| 545 if (preserve_result) { | 524 if (preserve_result) { |
| 546 __ Pop(R0); // Restore result. | 525 __ Pop(R0); // Restore result. |
| 547 } | 526 } |
| 548 __ LeaveStubFrame(); | 527 __ LeaveStubFrame(); |
| 549 // Remove materialization arguments. | 528 // Remove materialization arguments. |
| 550 __ add(SP, SP, Operand(R1)); | 529 __ add(SP, SP, Operand(R1)); |
| 551 __ ret(); | 530 __ ret(); |
| 552 } | 531 } |
| 553 | 532 |
| 554 | 533 |
| 555 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 534 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 556 // Correct return address to point just after the call that is being | 535 // Correct return address to point just after the call that is being |
| 557 // deoptimized. | 536 // deoptimized. |
| 558 __ AddImmediate(LR, LR, -CallPattern::kDeoptCallLengthInBytes); | 537 __ AddImmediate(LR, LR, -CallPattern::kLengthInBytes); |
| 559 // Push zap value instead of CODE_REG for lazy deopt. | 538 GenerateDeoptimizationSequence(assembler, true); // Preserve R0. |
| 560 __ LoadImmediate(TMP, 0xf1f1f1f1); | |
| 561 __ Push(TMP); | |
| 562 GenerateDeoptimizationSequence(assembler, kLazyDeopt); | |
| 563 } | 539 } |
| 564 | 540 |
| 565 | 541 |
| 566 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 542 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 567 GenerateDeoptimizationSequence(assembler, kEagerDeopt); | 543 GenerateDeoptimizationSequence(assembler, false); // Don't preserve R0. |
| 568 } | 544 } |
| 569 | 545 |
| 570 | 546 |
| 571 static void GenerateDispatcherCode(Assembler* assembler, | 547 static void GenerateDispatcherCode(Assembler* assembler, |
| 572 Label* call_target_function) { | 548 Label* call_target_function) { |
| 573 __ Comment("NoSuchMethodDispatch"); | 549 __ Comment("NoSuchMethodDispatch"); |
| 574 // When lazily generated invocation dispatchers are disabled, the | 550 // When lazily generated invocation dispatchers are disabled, the |
| 575 // miss-handler may return null. | 551 // miss-handler may return null. |
| 576 __ CompareObject(R0, Object::null_object()); | 552 __ CompareObject(R0, Object::null_object()); |
| 577 __ b(call_target_function, NE); | 553 __ b(call_target_function, NE); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 __ Push(R4); | 594 __ Push(R4); |
| 619 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); | 595 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); |
| 620 // Remove arguments. | 596 // Remove arguments. |
| 621 __ Drop(3); | 597 __ Drop(3); |
| 622 __ Pop(R0); // Get result into R0 (target function). | 598 __ Pop(R0); // Get result into R0 (target function). |
| 623 | 599 |
| 624 // Restore IC data and arguments descriptor. | 600 // Restore IC data and arguments descriptor. |
| 625 __ Pop(R4); | 601 __ Pop(R4); |
| 626 __ Pop(R5); | 602 __ Pop(R5); |
| 627 | 603 |
| 628 __ RestoreCodePointer(); | |
| 629 __ LeaveStubFrame(); | 604 __ LeaveStubFrame(); |
| 630 | 605 |
| 631 if (!FLAG_lazy_dispatchers) { | 606 if (!FLAG_lazy_dispatchers) { |
| 632 Label call_target_function; | 607 Label call_target_function; |
| 633 GenerateDispatcherCode(assembler, &call_target_function); | 608 GenerateDispatcherCode(assembler, &call_target_function); |
| 634 __ Bind(&call_target_function); | 609 __ Bind(&call_target_function); |
| 635 } | 610 } |
| 636 | 611 |
| 637 // Tail-call to target function. | 612 // Tail-call to target function. |
| 638 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 639 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | 613 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| 640 __ br(R2); | 614 __ br(R2); |
| 641 } | 615 } |
| 642 | 616 |
| 643 | 617 |
| 644 // Called for inline allocation of arrays. | 618 // Called for inline allocation of arrays. |
| 645 // Input parameters: | 619 // Input parameters: |
| 646 // LR: return address. | 620 // LR: return address. |
| 647 // R2: array length as Smi. | 621 // R2: array length as Smi. |
| 648 // R1: array element type (either NULL or an instantiated type). | 622 // R1: array element type (either NULL or an instantiated type). |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 __ Pop(R2); | 759 __ Pop(R2); |
| 786 __ Pop(R0); | 760 __ Pop(R0); |
| 787 __ LeaveStubFrame(); | 761 __ LeaveStubFrame(); |
| 788 __ ret(); | 762 __ ret(); |
| 789 } | 763 } |
| 790 | 764 |
| 791 | 765 |
| 792 // Called when invoking Dart code from C++ (VM code). | 766 // Called when invoking Dart code from C++ (VM code). |
| 793 // Input parameters: | 767 // Input parameters: |
| 794 // LR : points to return address. | 768 // LR : points to return address. |
| 795 // R0 : code object of the Dart function to call. | 769 // R0 : entrypoint of the Dart function to call. |
| 796 // R1 : arguments descriptor array. | 770 // R1 : arguments descriptor array. |
| 797 // R2 : arguments array. | 771 // R2 : arguments array. |
| 798 // R3 : current thread. | 772 // R3 : current thread. |
| 799 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { | 773 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
| 800 __ Comment("InvokeDartCodeStub"); | 774 __ Comment("InvokeDartCodeStub"); |
| 801 | 775 |
| 802 // Copy the C stack pointer (R31) into the stack pointer we'll actually use | 776 // Copy the C stack pointer (R31) into the stack pointer we'll actually use |
| 803 // to access the stack, and put the C stack pointer at the stack limit. | 777 // to access the stack, and put the C stack pointer at the stack limit. |
| 804 __ SetupDartSP(Isolate::GetSpecifiedStackSize()); | 778 __ SetupDartSP(Isolate::GetSpecifiedStackSize()); |
| 805 __ EnterFrame(0); | 779 __ EnterFrame(0); |
| 806 | 780 |
| 807 // Save the callee-saved registers. | 781 // Save the callee-saved registers. |
| 808 for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) { | 782 for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) { |
| 809 const Register r = static_cast<Register>(i); | 783 const Register r = static_cast<Register>(i); |
| 810 // We use str instead of the Push macro because we will be pushing the PP | 784 // We use str instead of the Push macro because we will be pushing the PP |
| 811 // register when it is not holding a pool-pointer since we are coming from | 785 // register when it is not holding a pool-pointer since we are coming from |
| 812 // C++ code. | 786 // C++ code. |
| 813 __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); | 787 __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); |
| 814 } | 788 } |
| 815 | 789 |
| 816 // Save the bottom 64-bits of callee-saved V registers. | 790 // Save the bottom 64-bits of callee-saved V registers. |
| 817 for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) { | 791 for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) { |
| 818 const VRegister r = static_cast<VRegister>(i); | 792 const VRegister r = static_cast<VRegister>(i); |
| 819 __ PushDouble(r); | 793 __ PushDouble(r); |
| 820 } | 794 } |
| 821 | 795 |
| 796 // We now load the pool pointer(PP) as we are about to invoke dart code and we |
| 797 // could potentially invoke some intrinsic functions which need the PP to be |
| 798 // set up. |
| 799 __ LoadPoolPointer(); |
| 800 |
| 822 // Set up THR, which caches the current thread in Dart code. | 801 // Set up THR, which caches the current thread in Dart code. |
| 823 if (THR != R3) { | 802 if (THR != R3) { |
| 824 __ mov(THR, R3); | 803 __ mov(THR, R3); |
| 825 } | 804 } |
| 826 // Load Isolate pointer into temporary register R5. | 805 // Load Isolate pointer into temporary register R5. |
| 827 __ LoadIsolate(R5); | 806 __ LoadIsolate(R5); |
| 828 | 807 |
| 829 // Save the current VMTag on the stack. | 808 // Save the current VMTag on the stack. |
| 830 __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset()); | 809 __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset()); |
| 831 __ Push(R4); | 810 __ Push(R4); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 864 __ LoadImmediate(R1, 0); | 843 __ LoadImmediate(R1, 0); |
| 865 __ Bind(&push_arguments); | 844 __ Bind(&push_arguments); |
| 866 __ ldr(R3, Address(R2)); | 845 __ ldr(R3, Address(R2)); |
| 867 __ Push(R3); | 846 __ Push(R3); |
| 868 __ add(R1, R1, Operand(1)); | 847 __ add(R1, R1, Operand(1)); |
| 869 __ add(R2, R2, Operand(kWordSize)); | 848 __ add(R2, R2, Operand(kWordSize)); |
| 870 __ cmp(R1, Operand(R5)); | 849 __ cmp(R1, Operand(R5)); |
| 871 __ b(&push_arguments, LT); | 850 __ b(&push_arguments, LT); |
| 872 __ Bind(&done_push_arguments); | 851 __ Bind(&done_push_arguments); |
| 873 | 852 |
| 874 // We now load the pool pointer(PP) with a GC safe value as we are about to | |
| 875 // invoke dart code. We don't need a real object pool here. | |
| 876 // Smi zero does not work because ARM64 assumes PP to be untagged. | |
| 877 __ LoadObject(PP, Object::null_object()); | |
| 878 | |
| 879 // Call the Dart code entrypoint. | 853 // Call the Dart code entrypoint. |
| 880 __ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle)); | |
| 881 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); | |
| 882 __ blr(R0); // R4 is the arguments descriptor array. | 854 __ blr(R0); // R4 is the arguments descriptor array. |
| 883 __ Comment("InvokeDartCodeStub return"); | 855 __ Comment("InvokeDartCodeStub return"); |
| 884 | 856 |
| 857 // Restore constant pool pointer after return. |
| 858 __ LoadPoolPointer(); |
| 859 |
| 885 // Get rid of arguments pushed on the stack. | 860 // Get rid of arguments pushed on the stack. |
| 886 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); | 861 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); |
| 887 | 862 |
| 888 __ LoadIsolate(R28); | 863 __ LoadIsolate(R28); |
| 889 | 864 |
| 890 // Restore the saved top exit frame info and top resource back into the | 865 // Restore the saved top exit frame info and top resource back into the |
| 891 // Isolate structure. Uses R6 as a temporary register for this. | 866 // Isolate structure. Uses R6 as a temporary register for this. |
| 892 __ Pop(R6); | 867 __ Pop(R6); |
| 893 __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset()); | 868 __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset()); |
| 894 __ Pop(R6); | 869 __ Pop(R6); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 906 | 881 |
| 907 // Restore C++ ABI callee-saved registers. | 882 // Restore C++ ABI callee-saved registers. |
| 908 for (int i = kAbiLastPreservedCpuReg; i >= kAbiFirstPreservedCpuReg; i--) { | 883 for (int i = kAbiLastPreservedCpuReg; i >= kAbiFirstPreservedCpuReg; i--) { |
| 909 Register r = static_cast<Register>(i); | 884 Register r = static_cast<Register>(i); |
| 910 // We use ldr instead of the Pop macro because we will be popping the PP | 885 // We use ldr instead of the Pop macro because we will be popping the PP |
| 911 // register when it is not holding a pool-pointer since we are returning to | 886 // register when it is not holding a pool-pointer since we are returning to |
| 912 // C++ code. We also skip the dart stack pointer SP, since we are still | 887 // C++ code. We also skip the dart stack pointer SP, since we are still |
| 913 // using it as the stack pointer. | 888 // using it as the stack pointer. |
| 914 __ ldr(r, Address(SP, 1 * kWordSize, Address::PostIndex)); | 889 __ ldr(r, Address(SP, 1 * kWordSize, Address::PostIndex)); |
| 915 } | 890 } |
| 891 __ set_constant_pool_allowed(false); |
| 916 | 892 |
| 917 // Restore the frame pointer and C stack pointer and return. | 893 // Restore the frame pointer and C stack pointer and return. |
| 918 __ LeaveFrame(); | 894 __ LeaveFrame(); |
| 919 __ mov(CSP, SP); | 895 __ mov(CSP, SP); |
| 920 __ ret(); | 896 __ ret(); |
| 921 } | 897 } |
| 922 | 898 |
| 923 | 899 |
| 924 // Called for inline allocation of contexts. | 900 // Called for inline allocation of contexts. |
| 925 // Input: | 901 // Input: |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1091 // Restore callee-saved registers, tear down frame. | 1067 // Restore callee-saved registers, tear down frame. |
| 1092 __ LeaveCallRuntimeFrame(); | 1068 __ LeaveCallRuntimeFrame(); |
| 1093 __ ret(); | 1069 __ ret(); |
| 1094 } | 1070 } |
| 1095 | 1071 |
| 1096 | 1072 |
| 1097 // Called for inline allocation of objects. | 1073 // Called for inline allocation of objects. |
| 1098 // Input parameters: | 1074 // Input parameters: |
| 1099 // LR : return address. | 1075 // LR : return address. |
| 1100 // SP + 0 : type arguments object (only if class is parameterized). | 1076 // SP + 0 : type arguments object (only if class is parameterized). |
| 1101 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, | 1077 void StubCode::GenerateAllocationStubForClass( |
| 1102 const Class& cls) { | 1078 Assembler* assembler, const Class& cls, |
| 1079 uword* entry_patch_offset, uword* patch_code_pc_offset) { |
| 1080 *entry_patch_offset = assembler->CodeSize(); |
| 1103 // The generated code is different if the class is parameterized. | 1081 // The generated code is different if the class is parameterized. |
| 1104 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 1082 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
| 1105 ASSERT(!is_cls_parameterized || | 1083 ASSERT(!is_cls_parameterized || |
| 1106 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); | 1084 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
| 1107 // kInlineInstanceSize is a constant used as a threshold for determining | 1085 // kInlineInstanceSize is a constant used as a threshold for determining |
| 1108 // when the object initialization should be done as a loop or as | 1086 // when the object initialization should be done as a loop or as |
| 1109 // straight line code. | 1087 // straight line code. |
| 1110 const int kInlineInstanceSize = 12; | 1088 const int kInlineInstanceSize = 12; |
| 1111 const intptr_t instance_size = cls.instance_size(); | 1089 const intptr_t instance_size = cls.instance_size(); |
| 1112 ASSERT(instance_size > 0); | 1090 ASSERT(instance_size > 0); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 // Push null type arguments. | 1190 // Push null type arguments. |
| 1213 __ PushObject(Object::null_object()); | 1191 __ PushObject(Object::null_object()); |
| 1214 } | 1192 } |
| 1215 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1193 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 1216 __ Drop(2); // Pop arguments. | 1194 __ Drop(2); // Pop arguments. |
| 1217 __ Pop(R0); // Pop result (newly allocated object). | 1195 __ Pop(R0); // Pop result (newly allocated object). |
| 1218 // R0: new object | 1196 // R0: new object |
| 1219 // Restore the frame pointer. | 1197 // Restore the frame pointer. |
| 1220 __ LeaveStubFrame(); | 1198 __ LeaveStubFrame(); |
| 1221 __ ret(); | 1199 __ ret(); |
| 1200 *patch_code_pc_offset = assembler->CodeSize(); |
| 1201 __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry()); |
| 1222 } | 1202 } |
| 1223 | 1203 |
| 1224 | 1204 |
| 1225 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function | 1205 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function |
| 1226 // from the entry code of a dart function after an error in passed argument | 1206 // from the entry code of a dart function after an error in passed argument |
| 1227 // name or number is detected. | 1207 // name or number is detected. |
| 1228 // Input parameters: | 1208 // Input parameters: |
| 1229 // LR : return address. | 1209 // LR : return address. |
| 1230 // SP : address of last argument. | 1210 // SP : address of last argument. |
| 1231 // R4: arguments descriptor array. | 1211 // R4: arguments descriptor array. |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1528 // Pass IC data object. | 1508 // Pass IC data object. |
| 1529 __ Push(R5); | 1509 __ Push(R5); |
| 1530 __ CallRuntime(handle_ic_miss, num_args + 1); | 1510 __ CallRuntime(handle_ic_miss, num_args + 1); |
| 1531 // Remove the call arguments pushed earlier, including the IC data object. | 1511 // Remove the call arguments pushed earlier, including the IC data object. |
| 1532 __ Drop(num_args + 1); | 1512 __ Drop(num_args + 1); |
| 1533 // Pop returned function object into R0. | 1513 // Pop returned function object into R0. |
| 1534 // Restore arguments descriptor array and IC data array. | 1514 // Restore arguments descriptor array and IC data array. |
| 1535 __ Pop(R0); // Pop returned function object into R0. | 1515 __ Pop(R0); // Pop returned function object into R0. |
| 1536 __ Pop(R5); // Restore IC Data. | 1516 __ Pop(R5); // Restore IC Data. |
| 1537 __ Pop(R4); // Restore arguments descriptor array. | 1517 __ Pop(R4); // Restore arguments descriptor array. |
| 1538 if (range_collection_mode == kCollectRanges) { | |
| 1539 __ RestoreCodePointer(); | |
| 1540 } | |
| 1541 __ LeaveStubFrame(); | 1518 __ LeaveStubFrame(); |
| 1542 Label call_target_function; | 1519 Label call_target_function; |
| 1543 if (!FLAG_lazy_dispatchers) { | 1520 if (!FLAG_lazy_dispatchers) { |
| 1544 GenerateDispatcherCode(assembler, &call_target_function); | 1521 GenerateDispatcherCode(assembler, &call_target_function); |
| 1545 } else { | 1522 } else { |
| 1546 __ b(&call_target_function); | 1523 __ b(&call_target_function); |
| 1547 } | 1524 } |
| 1548 | 1525 |
| 1549 __ Bind(&found); | 1526 __ Bind(&found); |
| 1550 __ Comment("Update caller's counter"); | 1527 __ Comment("Update caller's counter"); |
| 1551 // R6: pointer to an IC data check group. | 1528 // R6: pointer to an IC data check group. |
| 1552 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1529 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1553 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1530 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1554 __ LoadFromOffset(R0, R6, target_offset); | 1531 __ LoadFromOffset(R0, R6, target_offset); |
| 1555 | 1532 |
| 1556 if (FLAG_optimization_counter_threshold >= 0) { | 1533 if (FLAG_optimization_counter_threshold >= 0) { |
| 1557 // Update counter. | 1534 // Update counter. |
| 1558 __ LoadFromOffset(R1, R6, count_offset); | 1535 __ LoadFromOffset(R1, R6, count_offset); |
| 1559 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1536 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1560 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); | 1537 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); |
| 1561 __ csel(R1, R2, R1, VS); // Overflow. | 1538 __ csel(R1, R2, R1, VS); // Overflow. |
| 1562 __ StoreToOffset(R1, R6, count_offset); | 1539 __ StoreToOffset(R1, R6, count_offset); |
| 1563 } | 1540 } |
| 1564 | 1541 |
| 1565 __ Comment("Call target"); | 1542 __ Comment("Call target"); |
| 1566 __ Bind(&call_target_function); | 1543 __ Bind(&call_target_function); |
| 1567 // R0: target function. | 1544 // R0: target function. |
| 1545 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| 1568 if (range_collection_mode == kCollectRanges) { | 1546 if (range_collection_mode == kCollectRanges) { |
| 1569 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | |
| 1570 __ ldr(R1, Address(SP, 0 * kWordSize)); | 1547 __ ldr(R1, Address(SP, 0 * kWordSize)); |
| 1571 if (num_args == 2) { | 1548 if (num_args == 2) { |
| 1572 __ ldr(R3, Address(SP, 1 * kWordSize)); | 1549 __ ldr(R3, Address(SP, 1 * kWordSize)); |
| 1573 } | 1550 } |
| 1574 __ EnterStubFrame(); | 1551 __ EnterStubFrame(); |
| 1575 __ Push(R5); | 1552 __ Push(R5); |
| 1576 if (num_args == 2) { | 1553 if (num_args == 2) { |
| 1577 __ Push(R3); | 1554 __ Push(R3); |
| 1578 } | 1555 } |
| 1579 __ Push(R1); | 1556 __ Push(R1); |
| 1580 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 1581 __ blr(R2); | 1557 __ blr(R2); |
| 1582 | 1558 |
| 1583 Label done; | 1559 Label done; |
| 1584 __ ldr(R5, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | 1560 __ ldr(R5, Address(FP, kFirstLocalSlotFromFp * kWordSize)); |
| 1585 __ UpdateRangeFeedback(R0, 2, R5, R1, R4, &done); | 1561 __ UpdateRangeFeedback(R0, 2, R5, R1, R4, &done); |
| 1586 __ Bind(&done); | 1562 __ Bind(&done); |
| 1587 __ LeaveStubFrame(); | 1563 __ LeaveStubFrame(); |
| 1588 __ ret(); | 1564 __ ret(); |
| 1589 } else { | 1565 } else { |
| 1590 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 1591 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | |
| 1592 __ br(R2); | 1566 __ br(R2); |
| 1593 } | 1567 } |
| 1594 | 1568 |
| 1595 if (FLAG_support_debugger && !optimized) { | 1569 if (FLAG_support_debugger && !optimized) { |
| 1596 __ Bind(&stepping); | 1570 __ Bind(&stepping); |
| 1597 __ EnterStubFrame(); | 1571 __ EnterStubFrame(); |
| 1598 __ Push(R5); // Preserve IC data. | 1572 __ Push(R5); // Preserve IC data. |
| 1599 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1573 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1600 __ Pop(R5); | 1574 __ Pop(R5); |
| 1601 __ RestoreCodePointer(); | |
| 1602 __ LeaveStubFrame(); | 1575 __ LeaveStubFrame(); |
| 1603 __ b(&done_stepping); | 1576 __ b(&done_stepping); |
| 1604 } | 1577 } |
| 1605 } | 1578 } |
| 1606 | 1579 |
| 1607 | 1580 |
| 1608 // Use inline cache data array to invoke the target or continue in inline | 1581 // Use inline cache data array to invoke the target or continue in inline |
| 1609 // cache miss handler. Stub for 1-argument check (receiver class). | 1582 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1610 // LR: return address. | 1583 // LR: return address. |
| 1611 // R5: inline cache data object. | 1584 // R5: inline cache data object. |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1736 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); | 1709 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); |
| 1737 __ csel(R1, R2, R1, VS); // Overflow. | 1710 __ csel(R1, R2, R1, VS); // Overflow. |
| 1738 __ StoreToOffset(R1, R6, count_offset); | 1711 __ StoreToOffset(R1, R6, count_offset); |
| 1739 } | 1712 } |
| 1740 | 1713 |
| 1741 // Load arguments descriptor into R4. | 1714 // Load arguments descriptor into R4. |
| 1742 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 1715 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| 1743 | 1716 |
| 1744 // Get function and call it, if possible. | 1717 // Get function and call it, if possible. |
| 1745 __ LoadFromOffset(R0, R6, target_offset); | 1718 __ LoadFromOffset(R0, R6, target_offset); |
| 1746 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 1747 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | 1719 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| 1748 __ br(R2); | 1720 __ br(R2); |
| 1749 | 1721 |
| 1750 if (FLAG_support_debugger) { | 1722 if (FLAG_support_debugger) { |
| 1751 __ Bind(&stepping); | 1723 __ Bind(&stepping); |
| 1752 __ EnterStubFrame(); | 1724 __ EnterStubFrame(); |
| 1753 __ Push(R5); // Preserve IC data. | 1725 __ Push(R5); // Preserve IC data. |
| 1754 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1726 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1755 __ Pop(R5); | 1727 __ Pop(R5); |
| 1756 __ RestoreCodePointer(); | |
| 1757 __ LeaveStubFrame(); | 1728 __ LeaveStubFrame(); |
| 1758 __ b(&done_stepping); | 1729 __ b(&done_stepping); |
| 1759 } | 1730 } |
| 1760 } | 1731 } |
| 1761 | 1732 |
| 1762 | 1733 |
| 1763 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1734 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1764 GenerateUsageCounterIncrement(assembler, R6); | 1735 GenerateUsageCounterIncrement(assembler, R6); |
| 1765 GenerateNArgsCheckInlineCacheStub( | 1736 GenerateNArgsCheckInlineCacheStub( |
| 1766 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1737 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1785 __ EnterStubFrame(); | 1756 __ EnterStubFrame(); |
| 1786 __ Push(R5); // Save IC Data. | 1757 __ Push(R5); // Save IC Data. |
| 1787 __ Push(R4); // Save arg. desc. | 1758 __ Push(R4); // Save arg. desc. |
| 1788 __ Push(R0); // Pass function. | 1759 __ Push(R0); // Pass function. |
| 1789 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1760 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1790 __ Pop(R0); // Restore argument. | 1761 __ Pop(R0); // Restore argument. |
| 1791 __ Pop(R4); // Restore arg desc. | 1762 __ Pop(R4); // Restore arg desc. |
| 1792 __ Pop(R5); // Restore IC Data. | 1763 __ Pop(R5); // Restore IC Data. |
| 1793 __ LeaveStubFrame(); | 1764 __ LeaveStubFrame(); |
| 1794 | 1765 |
| 1795 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 1796 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | 1766 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| 1797 __ br(R2); | 1767 __ br(R2); |
| 1798 } | 1768 } |
| 1799 | 1769 |
| 1800 | 1770 |
| 1801 // R5: Contains an ICData. | 1771 // R5: Contains an ICData. |
| 1802 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { | 1772 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { |
| 1803 __ EnterStubFrame(); | 1773 __ EnterStubFrame(); |
| 1804 __ Push(R5); | 1774 __ Push(R5); |
| 1805 __ PushObject(Object::null_object()); // Space for result. | 1775 __ PushObject(Object::null_object()); // Space for result. |
| 1806 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1776 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1807 __ Pop(CODE_REG); | 1777 __ Pop(R0); |
| 1808 __ Pop(R5); | 1778 __ Pop(R5); |
| 1809 __ LeaveStubFrame(); | 1779 __ LeaveStubFrame(); |
| 1810 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | |
| 1811 __ br(R0); | 1780 __ br(R0); |
| 1812 } | 1781 } |
| 1813 | 1782 |
| 1814 | 1783 |
| 1815 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { | 1784 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { |
| 1816 __ EnterStubFrame(); | 1785 __ EnterStubFrame(); |
| 1817 __ PushObject(Object::null_object()); // Space for result. | 1786 __ PushObject(Object::null_object()); // Space for result. |
| 1818 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1787 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1819 __ Pop(CODE_REG); | 1788 __ Pop(R0); |
| 1820 __ LeaveStubFrame(); | 1789 __ LeaveStubFrame(); |
| 1821 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | |
| 1822 __ br(R0); | 1790 __ br(R0); |
| 1823 } | 1791 } |
| 1824 | 1792 |
| 1825 // Called only from unoptimized code. All relevant registers have been saved. | 1793 // Called only from unoptimized code. All relevant registers have been saved. |
| 1826 void StubCode::GenerateDebugStepCheckStub( | 1794 void StubCode::GenerateDebugStepCheckStub( |
| 1827 Assembler* assembler) { | 1795 Assembler* assembler) { |
| 1828 // Check single stepping. | 1796 // Check single stepping. |
| 1829 Label stepping, done_stepping; | 1797 Label stepping, done_stepping; |
| 1830 __ LoadIsolate(R1); | 1798 __ LoadIsolate(R1); |
| 1831 __ LoadFromOffset( | 1799 __ LoadFromOffset( |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1989 // R6: function to be re-optimized. | 1957 // R6: function to be re-optimized. |
| 1990 // R4: argument descriptor (preserved). | 1958 // R4: argument descriptor (preserved). |
| 1991 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { | 1959 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
| 1992 __ EnterStubFrame(); | 1960 __ EnterStubFrame(); |
| 1993 __ Push(R4); | 1961 __ Push(R4); |
| 1994 // Setup space on stack for the return value. | 1962 // Setup space on stack for the return value. |
| 1995 __ PushObject(Object::null_object()); | 1963 __ PushObject(Object::null_object()); |
| 1996 __ Push(R6); | 1964 __ Push(R6); |
| 1997 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); | 1965 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
| 1998 __ Pop(R0); // Discard argument. | 1966 __ Pop(R0); // Discard argument. |
| 1999 __ Pop(CODE_REG); // Get Code object | 1967 __ Pop(R0); // Get Code object |
| 2000 __ Pop(R4); // Restore argument descriptor. | 1968 __ Pop(R4); // Restore argument descriptor. |
| 2001 __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); | 1969 __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
| 2002 __ LeaveStubFrame(); | 1970 __ LeaveStubFrame(); |
| 2003 __ br(R0); | 1971 __ br(R0); |
| 2004 __ brk(0); | 1972 __ brk(0); |
| 2005 } | 1973 } |
| 2006 | 1974 |
| 2007 | 1975 |
| 2008 // Does identical check (object references are equal or not equal) with special | 1976 // Does identical check (object references are equal or not equal) with special |
| 2009 // checks for boxed numbers. | 1977 // checks for boxed numbers. |
| 2010 // Left and right are pushed on stack. | 1978 // Left and right are pushed on stack. |
| 2011 // Return Zero condition flag set if equal. | 1979 // Return Zero condition flag set if equal. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2084 const Register right = R0; | 2052 const Register right = R0; |
| 2085 __ LoadFromOffset(left, SP, 1 * kWordSize); | 2053 __ LoadFromOffset(left, SP, 1 * kWordSize); |
| 2086 __ LoadFromOffset(right, SP, 0 * kWordSize); | 2054 __ LoadFromOffset(right, SP, 0 * kWordSize); |
| 2087 GenerateIdenticalWithNumberCheckStub(assembler, left, right); | 2055 GenerateIdenticalWithNumberCheckStub(assembler, left, right); |
| 2088 __ ret(); | 2056 __ ret(); |
| 2089 | 2057 |
| 2090 if (FLAG_support_debugger) { | 2058 if (FLAG_support_debugger) { |
| 2091 __ Bind(&stepping); | 2059 __ Bind(&stepping); |
| 2092 __ EnterStubFrame(); | 2060 __ EnterStubFrame(); |
| 2093 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 2061 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 2094 __ RestoreCodePointer(); | |
| 2095 __ LeaveStubFrame(); | 2062 __ LeaveStubFrame(); |
| 2096 __ b(&done_stepping); | 2063 __ b(&done_stepping); |
| 2097 } | 2064 } |
| 2098 } | 2065 } |
| 2099 | 2066 |
| 2100 | 2067 |
| 2101 // Called from optimized code only. | 2068 // Called from optimized code only. |
| 2102 // LR: return address. | 2069 // LR: return address. |
| 2103 // SP + 4: left operand. | 2070 // SP + 4: left operand. |
| 2104 // SP + 0: right operand. | 2071 // SP + 0: right operand. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2143 __ CompareRegisters(R4, R0); | 2110 __ CompareRegisters(R4, R0); |
| 2144 __ b(&update, NE); | 2111 __ b(&update, NE); |
| 2145 | 2112 |
| 2146 __ Bind(&call_target_function); | 2113 __ Bind(&call_target_function); |
| 2147 // Call the target found in the cache. For a class id match, this is a | 2114 // Call the target found in the cache. For a class id match, this is a |
| 2148 // proper target for the given name and arguments descriptor. If the | 2115 // proper target for the given name and arguments descriptor. If the |
| 2149 // illegal class id was found, the target is a cache miss handler that can | 2116 // illegal class id was found, the target is a cache miss handler that can |
| 2150 // be invoked as a normal Dart function. | 2117 // be invoked as a normal Dart function. |
| 2151 __ add(TMP, R2, Operand(R3, LSL, 3)); | 2118 __ add(TMP, R2, Operand(R3, LSL, 3)); |
| 2152 __ LoadFieldFromOffset(R0, TMP, base + kWordSize); | 2119 __ LoadFieldFromOffset(R0, TMP, base + kWordSize); |
| 2153 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | |
| 2154 __ LoadFieldFromOffset(R1, R0, Function::entry_point_offset()); | 2120 __ LoadFieldFromOffset(R1, R0, Function::entry_point_offset()); |
| 2155 } | 2121 } |
| 2156 | 2122 |
| 2157 | 2123 |
| 2158 // Called from megamorphic calls. | 2124 // Called from megamorphic calls. |
| 2159 // R0: receiver. | 2125 // R0: receiver. |
| 2160 // R1: lookup cache. | 2126 // R1: lookup cache. |
| 2161 // Result: | 2127 // Result: |
| 2162 // R1: entry point. | 2128 // R1: entry point. |
| 2163 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { | 2129 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
| 2164 EmitMegamorphicLookup(assembler, R0, R1, R1); | 2130 EmitMegamorphicLookup(assembler, R0, R1, R1); |
| 2165 __ ret(); | 2131 __ ret(); |
| 2166 } | 2132 } |
| 2167 | 2133 |
| 2168 } // namespace dart | 2134 } // namespace dart |
| 2169 | 2135 |
| 2170 #endif // defined TARGET_ARCH_ARM64 | 2136 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |