Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: runtime/vm/stub_code_x64.cc

Issue 2374273002: Fix a throw returning to a frame marked for lazy deopt that captures the stacktrace. (Closed)
Patch Set: . Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/stub_code_mips.cc ('k') | tests/language/vm/lazy_deopt_with_exception_and_stacktrace_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698