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 |