| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 static void GenerateDeoptimizationSequence(Assembler* assembler, | 378 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 379 DeoptStubKind kind) { | 379 DeoptStubKind kind) { |
| 380 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 380 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 381 // is no need to set the correct PC marker or load PP, since they get patched. | 381 // is no need to set the correct PC marker or load PP, since they get patched. |
| 382 __ EnterStubFrame(); | 382 __ EnterStubFrame(); |
| 383 | 383 |
| 384 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry | 384 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 385 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. | 385 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 386 const intptr_t saved_result_slot_from_fp = | 386 const intptr_t saved_result_slot_from_fp = |
| 387 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - RAX); | 387 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - RAX); |
| 388 const intptr_t saved_exception_slot_from_fp = |
| 389 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - RAX); |
| 390 const intptr_t saved_stacktrace_slot_from_fp = |
| 391 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - RDX); |
| 388 // Result in RAX is preserved as part of pushing all registers below. | 392 // Result in RAX is preserved as part of pushing all registers below. |
| 389 | 393 |
| 390 // Push registers in their enumeration order: lowest register number at | 394 // Push registers in their enumeration order: lowest register number at |
| 391 // lowest address. | 395 // lowest address. |
| 392 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { | 396 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
| 393 if (i == CODE_REG) { | 397 if (i == CODE_REG) { |
| 394 // Save the original value of CODE_REG pushed before invoking this stub | 398 // Save the original value of CODE_REG pushed before invoking this stub |
| 395 // instead of the value used to call this stub. | 399 // instead of the value used to call this stub. |
| 396 __ pushq(Address(RBP, 2 * kWordSize)); | 400 __ pushq(Address(RBP, 2 * kWordSize)); |
| 397 } else { | 401 } else { |
| 398 __ pushq(static_cast<Register>(i)); | 402 __ pushq(static_cast<Register>(i)); |
| 399 } | 403 } |
| 400 } | 404 } |
| 401 __ subq(RSP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize)); | 405 __ subq(RSP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize)); |
| 402 intptr_t offset = 0; | 406 intptr_t offset = 0; |
| 403 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | 407 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 404 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | 408 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 405 __ movups(Address(RSP, offset), xmm_reg); | 409 __ movups(Address(RSP, offset), xmm_reg); |
| 406 offset += kFpuRegisterSize; | 410 offset += kFpuRegisterSize; |
| 407 } | 411 } |
| 408 | 412 |
| 409 // Pass address of saved registers block. | 413 // Pass address of saved registers block. |
| 410 __ movq(CallingConventions::kArg1Reg, RSP); | 414 __ movq(CallingConventions::kArg1Reg, RSP); |
| 411 __ movq(CallingConventions::kArg2Reg, Immediate(kind == kLazyDeopt ? 1 : 0)); | 415 bool is_lazy = (kind == kLazyDeoptFromReturn) || |
| 416 (kind == kLazyDeoptFromThrow); |
| 417 __ movq(CallingConventions::kArg2Reg, Immediate(is_lazy ? 1 : 0)); |
| 412 __ ReserveAlignedFrameSpace(0); // Ensure stack is aligned before the call. | 418 __ ReserveAlignedFrameSpace(0); // Ensure stack is aligned before the call. |
| 413 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); | 419 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); |
| 414 // Result (RAX) is stack-size (FP - SP) in bytes. | 420 // Result (RAX) is stack-size (FP - SP) in bytes. |
| 415 | 421 |
| 416 const bool preserve_result = (kind == kLazyDeopt); | 422 if (kind == kLazyDeoptFromReturn) { |
| 417 if (preserve_result) { | |
| 418 // Restore result into RBX temporarily. | 423 // Restore result into RBX temporarily. |
| 419 __ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize)); | 424 __ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize)); |
| 425 } else if (kind == kLazyDeoptFromThrow) { |
| 426 // Restore result into RBX temporarily. |
| 427 __ movq(RBX, Address(RBP, saved_exception_slot_from_fp * kWordSize)); |
| 428 __ movq(RDX, Address(RBP, saved_stacktrace_slot_from_fp * kWordSize)); |
| 420 } | 429 } |
| 421 | 430 |
| 422 // There is a Dart Frame on the stack. We must restore PP and leave frame. | 431 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 423 __ RestoreCodePointer(); | 432 __ RestoreCodePointer(); |
| 424 __ LeaveStubFrame(); | 433 __ LeaveStubFrame(); |
| 425 | 434 |
| 426 __ popq(RCX); // Preserve return address. | 435 __ popq(RCX); // Preserve return address. |
| 427 __ movq(RSP, RBP); // Discard optimized frame. | 436 __ movq(RSP, RBP); // Discard optimized frame. |
| 428 __ subq(RSP, RAX); // Reserve space for deoptimized frame. | 437 __ subq(RSP, RAX); // Reserve space for deoptimized frame. |
| 429 __ pushq(RCX); // Restore return address. | 438 __ pushq(RCX); // Restore return address. |
| 430 | 439 |
| 431 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 440 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 432 // is no need to set the correct PC marker or load PP, since they get patched. | 441 // is no need to set the correct PC marker or load PP, since they get patched. |
| 433 __ EnterStubFrame(); | 442 __ EnterStubFrame(); |
| 434 | 443 |
| 435 if (preserve_result) { | 444 if (kind == kLazyDeoptFromReturn) { |
| 436 __ pushq(RBX); // Preserve result as first local. | 445 __ pushq(RBX); // Preserve result as first local. |
| 446 } else if (kind == kLazyDeoptFromThrow) { |
| 447 __ pushq(RBX); // Preserve exception as first local. |
| 448 __ pushq(RDX); // Preserve stacktrace as second local. |
| 437 } | 449 } |
| 438 __ ReserveAlignedFrameSpace(0); | 450 __ ReserveAlignedFrameSpace(0); |
| 439 // Pass last FP as a parameter. | 451 // Pass last FP as a parameter. |
| 440 __ movq(CallingConventions::kArg1Reg, RBP); | 452 __ movq(CallingConventions::kArg1Reg, RBP); |
| 441 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); | 453 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); |
| 442 if (preserve_result) { | 454 if (kind == kLazyDeoptFromReturn) { |
| 443 // Restore result into RBX. | 455 // Restore result into RBX. |
| 444 __ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize)); | 456 __ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize)); |
| 457 } else if (kind == kLazyDeoptFromThrow) { |
| 458 // Restore exception into RBX. |
| 459 __ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize)); |
| 460 // Restore stacktrace into RDX. |
| 461 __ movq(RDX, Address(RBP, (kFirstLocalSlotFromFp - 1) * kWordSize)); |
| 445 } | 462 } |
| 446 // Code above cannot cause GC. | 463 // Code above cannot cause GC. |
| 447 // There is a Dart Frame on the stack. We must restore PP and leave frame. | 464 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 448 __ RestoreCodePointer(); | 465 __ RestoreCodePointer(); |
| 449 __ LeaveStubFrame(); | 466 __ LeaveStubFrame(); |
| 450 | 467 |
| 451 // Frame is fully rewritten at this point and it is safe to perform a GC. | 468 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 452 // Materialize any objects that were deferred by FillFrame because they | 469 // Materialize any objects that were deferred by FillFrame because they |
| 453 // require allocation. | 470 // require allocation. |
| 454 // Enter stub frame with loading PP. The caller's PP is not materialized yet. | 471 // Enter stub frame with loading PP. The caller's PP is not materialized yet. |
| 455 __ EnterStubFrame(); | 472 __ EnterStubFrame(); |
| 456 if (preserve_result) { | 473 if (kind == kLazyDeoptFromReturn) { |
| 457 __ pushq(RBX); // Preserve result, it will be GC-d here. | 474 __ pushq(RBX); // Preserve result, it will be GC-d here. |
| 475 } else if (kind == kLazyDeoptFromThrow) { |
| 476 __ pushq(RBX); // Preserve exception. |
| 477 __ pushq(RDX); // Preserve stacktrace. |
| 458 } | 478 } |
| 459 __ pushq(Immediate(Smi::RawValue(0))); // Space for the result. | 479 __ pushq(Immediate(Smi::RawValue(0))); // Space for the result. |
| 460 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); | 480 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); |
| 461 // Result tells stub how many bytes to remove from the expression stack | 481 // Result tells stub how many bytes to remove from the expression stack |
| 462 // of the bottom-most frame. They were used as materialization arguments. | 482 // of the bottom-most frame. They were used as materialization arguments. |
| 463 __ popq(RBX); | 483 __ popq(RBX); |
| 464 __ SmiUntag(RBX); | 484 __ SmiUntag(RBX); |
| 465 if (preserve_result) { | 485 if (kind == kLazyDeoptFromReturn) { |
| 466 __ popq(RAX); // Restore result. | 486 __ popq(RAX); // Restore result. |
| 487 } else if (kind == kLazyDeoptFromThrow) { |
| 488 __ popq(RDX); // Restore stacktrace. |
| 489 __ popq(RAX); // Restore exception. |
| 467 } | 490 } |
| 468 __ LeaveStubFrame(); | 491 __ LeaveStubFrame(); |
| 469 | 492 |
| 470 __ popq(RCX); // Pop return address. | 493 __ popq(RCX); // Pop return address. |
| 471 __ addq(RSP, RBX); // Remove materialization arguments. | 494 __ addq(RSP, RBX); // Remove materialization arguments. |
| 472 __ pushq(RCX); // Push return address. | 495 __ pushq(RCX); // Push return address. |
| 473 __ ret(); | 496 __ ret(); |
| 474 } | 497 } |
| 475 | 498 |
| 476 | 499 |
| 477 // TOS: return address + call-instruction-size (5 bytes). | 500 // TOS: return address + call-instruction-size (5 bytes). |
| 478 // RAX: result, must be preserved | 501 // RAX: result, must be preserved |
| 479 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 502 void StubCode::GenerateDeoptimizeLazyFromReturnStub(Assembler* assembler) { |
| 480 // Correct return address to point just after the call that is being | 503 // Correct return address to point just after the call that is being |
| 481 // deoptimized. | 504 // deoptimized. |
| 482 __ popq(RBX); | 505 __ popq(RBX); |
| 506 __ subq(RBX, Immediate(ShortCallPattern::pattern_length_in_bytes())); |
| 507 // Push zap value instead of CODE_REG for lazy deopt. |
| 508 __ pushq(Immediate(0xf1f1f1f1)); |
| 509 __ pushq(RBX); |
| 510 GenerateDeoptimizationSequence(assembler, kLazyDeoptFromReturn); |
| 511 } |
| 512 |
| 513 |
| 514 // TOS: return address + call-instruction-size (5 bytes). |
| 515 // RAX: exception, must be preserved |
| 516 // RDX: stacktrace, must be preserved |
| 517 void StubCode::GenerateDeoptimizeLazyFromThrowStub(Assembler* assembler) { |
| 518 // Correct return address to point just after the call that is being |
| 519 // deoptimized. |
| 520 __ popq(RBX); |
| 483 __ subq(RBX, Immediate(ShortCallPattern::pattern_length_in_bytes())); | 521 __ subq(RBX, Immediate(ShortCallPattern::pattern_length_in_bytes())); |
| 484 // Push zap value instead of CODE_REG for lazy deopt. | 522 // Push zap value instead of CODE_REG for lazy deopt. |
| 485 __ pushq(Immediate(0xf1f1f1f1)); | 523 __ pushq(Immediate(0xf1f1f1f1)); |
| 486 __ pushq(RBX); | 524 __ pushq(RBX); |
| 487 GenerateDeoptimizationSequence(assembler, kLazyDeopt); | 525 GenerateDeoptimizationSequence(assembler, kLazyDeoptFromThrow); |
| 488 } | 526 } |
| 489 | 527 |
| 490 | 528 |
| 491 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 529 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 492 GenerateDeoptimizationSequence(assembler, kEagerDeopt); | 530 GenerateDeoptimizationSequence(assembler, kEagerDeopt); |
| 493 } | 531 } |
| 494 | 532 |
| 495 | 533 |
| 496 static void GenerateDispatcherCode(Assembler* assembler, | 534 static void GenerateDispatcherCode(Assembler* assembler, |
| 497 Label* call_target_function) { | 535 Label* call_target_function) { |
| (...skipping 1747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 } | 2283 } |
| 2246 | 2284 |
| 2247 | 2285 |
| 2248 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2286 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2249 __ int3(); | 2287 __ int3(); |
| 2250 } | 2288 } |
| 2251 | 2289 |
| 2252 } // namespace dart | 2290 } // namespace dart |
| 2253 | 2291 |
| 2254 #endif // defined TARGET_ARCH_X64 | 2292 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |