OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/assembler_macros.h" | 9 #include "vm/assembler_macros.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 __ popq(RAX); // Get result into RAX. | 463 __ popq(RAX); // Get result into RAX. |
464 | 464 |
465 // Remove the stub frame as we are about to return. | 465 // Remove the stub frame as we are about to return. |
466 __ LeaveFrame(); | 466 __ LeaveFrame(); |
467 __ ret(); | 467 __ ret(); |
468 } | 468 } |
469 | 469 |
470 | 470 |
471 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 471 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
472 intptr_t deopt_reason, | 472 intptr_t deopt_reason, |
473 intptr_t* saved_registers_address); | 473 uword saved_registers_address); |
474 | 474 |
475 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); | 475 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); |
476 | 476 |
477 // This stub translates optimized frame into unoptimized frame. The optimized | 477 // This stub translates optimized frame into unoptimized frame. The optimized |
478 // frame can contain values in registers and on stack, the unoptimized | 478 // frame can contain values in registers and on stack, the unoptimized |
479 // frame contains all values on stack. | 479 // frame contains all values on stack. |
480 // Deoptimization occurs in following steps: | 480 // Deoptimization occurs in following steps: |
481 // - Push all registers that can contain values. | 481 // - Push all registers that can contain values. |
482 // - Call C routine to copy the stack and saved registers into temporary buffer. | 482 // - Call C routine to copy the stack and saved registers into temporary buffer. |
483 // - Adjust caller's frame to correct unoptimized frame size. | 483 // - Adjust caller's frame to correct unoptimized frame size. |
484 // - Fill the unoptimized frame. | 484 // - Fill the unoptimized frame. |
| 485 // - Materialize objects that require allocation (e.g. Double instances). |
| 486 // GC can occur only after frame is fully rewritten. |
485 // Stack: | 487 // Stack: |
486 // +------------------+ | 488 // +------------------+ |
487 // | 0 as PC marker | <- TOS | 489 // | 0 as PC marker | <- TOS |
488 // +------------------+ | 490 // +------------------+ |
489 // | Saved FP | | 491 // | Saved FP | |
490 // +------------------+ | 492 // +------------------+ |
491 // | return-address | (deoptimization point) | 493 // | return-address | (deoptimization point) |
492 // +------------------+ | 494 // +------------------+ |
493 // | optimized frame | | 495 // | optimized frame | |
494 // | ... | | 496 // | ... | |
495 // | 497 // |
496 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 498 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
497 __ EnterFrame(0); | 499 __ EnterFrame(0); |
498 // Push registers in their enumeration order: lowest register number at | 500 // Push registers in their enumeration order: lowest register number at |
499 // lowest address. | 501 // lowest address. |
500 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { | 502 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
501 __ pushq(static_cast<Register>(i)); | 503 __ pushq(static_cast<Register>(i)); |
502 } | 504 } |
| 505 __ subq(RSP, Immediate(kNumberOfXmmRegisters * kDoubleSize)); |
| 506 intptr_t offset = 0; |
| 507 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 508 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 509 __ movsd(Address(RSP, offset), xmm_reg); |
| 510 offset += kDoubleSize; |
| 511 } |
| 512 |
503 __ movq(RCX, RSP); // Saved saved registers block. | 513 __ movq(RCX, RSP); // Saved saved registers block. |
504 __ ReserveAlignedFrameSpace(0); | 514 __ ReserveAlignedFrameSpace(0); |
505 __ SmiUntag(RAX); | 515 __ SmiUntag(RAX); |
506 __ movq(RDI, RCX); // Set up argument 1 saved_registers_address. | 516 __ movq(RDI, RCX); // Set up argument 1 saved_registers_address. |
507 | 517 |
508 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry); | 518 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry); |
509 // Result (RAX) is stack-size (FP - SP) in bytes, incl. the return address. | 519 // Result (RAX) is stack-size (FP - SP) in bytes, incl. the return address. |
510 __ LeaveFrame(); | 520 __ LeaveFrame(); |
511 __ popq(RCX); // Preserve return address. | 521 __ popq(RCX); // Preserve return address. |
512 __ movq(RSP, RBP); | 522 __ movq(RSP, RBP); |
513 __ subq(RSP, RAX); | 523 __ subq(RSP, RAX); |
514 __ movq(Address(RSP, 0), RCX); | 524 __ movq(Address(RSP, 0), RCX); |
515 | 525 |
516 __ EnterFrame(0); | 526 __ EnterFrame(0); |
517 __ movq(RCX, RSP); // Get last FP address. | 527 __ movq(RCX, RSP); // Get last FP address. |
518 __ ReserveAlignedFrameSpace(0); | 528 __ ReserveAlignedFrameSpace(0); |
519 __ movq(RDI, RCX); // Set up argument 1 last_fp. | 529 __ movq(RDI, RCX); // Set up argument 1 last_fp. |
520 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); | 530 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); |
521 __ LeaveFrame(); | 531 __ LeaveFrame(); |
| 532 |
| 533 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 534 // Materialize any objects that were deferred by FillFrame because they |
| 535 // require allocation. |
| 536 __ EnterFrame(0); |
| 537 __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry); |
| 538 __ LeaveFrame(); |
| 539 |
522 __ ret(); | 540 __ ret(); |
523 } | 541 } |
524 | 542 |
525 | 543 |
526 // Called for inline allocation of arrays. | 544 // Called for inline allocation of arrays. |
527 // Input parameters: | 545 // Input parameters: |
528 // R10 : Array length as Smi. | 546 // R10 : Array length as Smi. |
529 // RBX : array element type (either NULL or an instantiated type). | 547 // RBX : array element type (either NULL or an instantiated type). |
530 // NOTE: R10 cannot be clobbered here as the caller relies on it being saved. | 548 // NOTE: R10 cannot be clobbered here as the caller relies on it being saved. |
531 // The newly allocated object is returned in RAX. | 549 // The newly allocated object is returned in RAX. |
(...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1847 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { | 1865 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { |
1848 __ movq(RAX, RCX); // error object. | 1866 __ movq(RAX, RCX); // error object. |
1849 __ movq(RBP, RDX); // target frame_pointer. | 1867 __ movq(RBP, RDX); // target frame_pointer. |
1850 __ movq(RSP, RSI); // target stack_pointer. | 1868 __ movq(RSP, RSI); // target stack_pointer. |
1851 __ jmp(RDI); // Jump to the exception handler code. | 1869 __ jmp(RDI); // Jump to the exception handler code. |
1852 } | 1870 } |
1853 | 1871 |
1854 } // namespace dart | 1872 } // namespace dart |
1855 | 1873 |
1856 #endif // defined TARGET_ARCH_X64 | 1874 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |