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 |