OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 #include <cmath> | 6 #include <cmath> |
7 #include <cstdarg> | 7 #include <cstdarg> |
8 #include "v8.h" | 8 #include "v8.h" |
9 | 9 |
10 #if V8_TARGET_ARCH_ARM64 | 10 #if V8_TARGET_ARCH_ARM64 |
(...skipping 3563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3574 ASSERT(pc_->ImmException() == kImmExceptionIsUnreachable); | 3574 ASSERT(pc_->ImmException() == kImmExceptionIsUnreachable); |
3575 // - Skip past the unreachable marker. | 3575 // - Skip past the unreachable marker. |
3576 set_pc(pc_->following()); | 3576 set_pc(pc_->following()); |
3577 | 3577 |
3578 // Check if the debugger should break. | 3578 // Check if the debugger should break. |
3579 if (parameters & BREAK) Debug(); | 3579 if (parameters & BREAK) Debug(); |
3580 | 3580 |
3581 } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) { | 3581 } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) { |
3582 DoRuntimeCall(instr); | 3582 DoRuntimeCall(instr); |
3583 } else if (instr->ImmException() == kImmExceptionIsPrintf) { | 3583 } else if (instr->ImmException() == kImmExceptionIsPrintf) { |
3584 // Read the argument encoded inline in the instruction stream. | 3584 DoPrintf(instr); |
3585 uint32_t type; | |
3586 memcpy(&type, | |
3587 pc_->InstructionAtOffset(kPrintfTypeOffset), | |
3588 sizeof(type)); | |
3589 | |
3590 const char* format = reg<const char*>(0); | |
3591 | |
3592 // Pass all of the relevant PCS registers onto printf. It doesn't | |
3593 // matter if we pass too many as the extra ones won't be read. | |
3594 int result; | |
3595 fputs(clr_printf, stream_); | |
3596 if (type == CPURegister::kRegister) { | |
3597 result = fprintf(stream_, format, | |
3598 xreg(1), xreg(2), xreg(3), xreg(4), | |
3599 xreg(5), xreg(6), xreg(7)); | |
3600 } else if (type == CPURegister::kFPRegister) { | |
3601 result = fprintf(stream_, format, | |
3602 dreg(0), dreg(1), dreg(2), dreg(3), | |
3603 dreg(4), dreg(5), dreg(6), dreg(7)); | |
3604 } else { | |
3605 ASSERT(type == CPURegister::kNoRegister); | |
3606 result = fprintf(stream_, "%s", format); | |
3607 } | |
3608 fputs(clr_normal, stream_); | |
3609 | |
3610 #ifdef DEBUG | |
3611 CorruptAllCallerSavedCPURegisters(); | |
3612 #endif | |
3613 | |
3614 set_xreg(0, result); | |
3615 | |
3616 // The printf parameters are inlined in the code, so skip them. | |
3617 set_pc(pc_->InstructionAtOffset(kPrintfLength)); | |
3618 | |
3619 // Set LR as if we'd just called a native printf function. | |
3620 set_lr(pc()); | |
3621 | 3585 |
3622 } else if (instr->ImmException() == kImmExceptionIsUnreachable) { | 3586 } else if (instr->ImmException() == kImmExceptionIsUnreachable) { |
3623 fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n", | 3587 fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n", |
3624 reinterpret_cast<void*>(pc_)); | 3588 reinterpret_cast<void*>(pc_)); |
3625 abort(); | 3589 abort(); |
3626 | 3590 |
3627 } else { | 3591 } else { |
3628 OS::DebugBreak(); | 3592 OS::DebugBreak(); |
3629 } | 3593 } |
3630 break; | 3594 break; |
3631 } | 3595 } |
3632 | 3596 |
3633 default: | 3597 default: |
3634 UNIMPLEMENTED(); | 3598 UNIMPLEMENTED(); |
3635 } | 3599 } |
3636 } | 3600 } |
3637 | 3601 |
| 3602 |
| 3603 void Simulator::DoPrintf(Instruction* instr) { |
| 3604 ASSERT((instr->Mask(ExceptionMask) == HLT) && |
| 3605 (instr->ImmException() == kImmExceptionIsPrintf)); |
| 3606 |
| 3607 // Read the arguments encoded inline in the instruction stream. |
| 3608 uint32_t arg_count; |
| 3609 uint32_t arg_pattern_list; |
| 3610 STATIC_ASSERT(sizeof(*instr) == 1); |
| 3611 memcpy(&arg_count, |
| 3612 instr + kPrintfArgCountOffset, |
| 3613 sizeof(arg_count)); |
| 3614 memcpy(&arg_pattern_list, |
| 3615 instr + kPrintfArgPatternListOffset, |
| 3616 sizeof(arg_pattern_list)); |
| 3617 |
| 3618 ASSERT(arg_count <= kPrintfMaxArgCount); |
| 3619 ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0); |
| 3620 |
| 3621 // We need to call the host printf function with a set of arguments defined by |
| 3622 // arg_pattern_list. Because we don't know the types and sizes of the |
| 3623 // arguments, this is very difficult to do in a robust and portable way. To |
| 3624 // work around the problem, we pick apart the format string, and print one |
| 3625 // format placeholder at a time. |
| 3626 |
| 3627 // Allocate space for the format string. We take a copy, so we can modify it. |
| 3628 // Leave enough space for one extra character per expected argument (plus the |
| 3629 // '\0' termination). |
| 3630 const char * format_base = reg<const char *>(0); |
| 3631 ASSERT(format_base != NULL); |
| 3632 size_t length = strlen(format_base) + 1; |
| 3633 char * const format = new char[length + arg_count]; |
| 3634 |
| 3635 // A list of chunks, each with exactly one format placeholder. |
| 3636 const char * chunks[kPrintfMaxArgCount]; |
| 3637 |
| 3638 // Copy the format string and search for format placeholders. |
| 3639 uint32_t placeholder_count = 0; |
| 3640 char * format_scratch = format; |
| 3641 for (size_t i = 0; i < length; i++) { |
| 3642 if (format_base[i] != '%') { |
| 3643 *format_scratch++ = format_base[i]; |
| 3644 } else { |
| 3645 if (format_base[i + 1] == '%') { |
| 3646 // Ignore explicit "%%" sequences. |
| 3647 *format_scratch++ = format_base[i]; |
| 3648 |
| 3649 if (placeholder_count == 0) { |
| 3650 // The first chunk is passed to printf using "%s", so we need to |
| 3651 // unescape "%%" sequences in this chunk. (Just skip the next '%'.) |
| 3652 i++; |
| 3653 } else { |
| 3654 // Otherwise, pass through "%%" unchanged. |
| 3655 *format_scratch++ = format_base[++i]; |
| 3656 } |
| 3657 } else { |
| 3658 CHECK(placeholder_count < arg_count); |
| 3659 // Insert '\0' before placeholders, and store their locations. |
| 3660 *format_scratch++ = '\0'; |
| 3661 chunks[placeholder_count++] = format_scratch; |
| 3662 *format_scratch++ = format_base[i]; |
| 3663 } |
| 3664 } |
| 3665 } |
| 3666 ASSERT(format_scratch <= (format + length + arg_count)); |
| 3667 CHECK(placeholder_count == arg_count); |
| 3668 |
| 3669 // Finally, call printf with each chunk, passing the appropriate register |
| 3670 // argument. Normally, printf returns the number of bytes transmitted, so we |
| 3671 // can emulate a single printf call by adding the result from each chunk. If |
| 3672 // any call returns a negative (error) value, though, just return that value. |
| 3673 |
| 3674 fprintf(stream_, "%s", clr_printf); |
| 3675 |
| 3676 // Because '\0' is inserted before each placeholder, the first string in |
| 3677 // 'format' contains no format placeholders and should be printed literally. |
| 3678 int result = fprintf(stream_, "%s", format); |
| 3679 int pcs_r = 1; // Start at x1. x0 holds the format string. |
| 3680 int pcs_f = 0; // Start at d0. |
| 3681 if (result >= 0) { |
| 3682 for (uint32_t i = 0; i < placeholder_count; i++) { |
| 3683 int part_result = -1; |
| 3684 |
| 3685 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits); |
| 3686 arg_pattern &= (1 << kPrintfArgPatternBits) - 1; |
| 3687 switch (arg_pattern) { |
| 3688 case kPrintfArgW: |
| 3689 part_result = fprintf(stream_, chunks[i], wreg(pcs_r++)); |
| 3690 break; |
| 3691 case kPrintfArgX: |
| 3692 part_result = fprintf(stream_, chunks[i], xreg(pcs_r++)); |
| 3693 break; |
| 3694 case kPrintfArgD: |
| 3695 part_result = fprintf(stream_, chunks[i], dreg(pcs_f++)); |
| 3696 break; |
| 3697 default: UNREACHABLE(); |
| 3698 } |
| 3699 |
| 3700 if (part_result < 0) { |
| 3701 // Handle error values. |
| 3702 result = part_result; |
| 3703 break; |
| 3704 } |
| 3705 |
| 3706 result += part_result; |
| 3707 } |
| 3708 } |
| 3709 |
| 3710 fprintf(stream_, "%s", clr_normal); |
| 3711 |
| 3712 #ifdef DEBUG |
| 3713 CorruptAllCallerSavedCPURegisters(); |
| 3714 #endif |
| 3715 |
| 3716 // Printf returns its result in x0 (just like the C library's printf). |
| 3717 set_xreg(0, result); |
| 3718 |
| 3719 // The printf parameters are inlined in the code, so skip them. |
| 3720 set_pc(instr->InstructionAtOffset(kPrintfLength)); |
| 3721 |
| 3722 // Set LR as if we'd just called a native printf function. |
| 3723 set_lr(pc()); |
| 3724 |
| 3725 delete[] format; |
| 3726 } |
| 3727 |
| 3728 |
3638 #endif // USE_SIMULATOR | 3729 #endif // USE_SIMULATOR |
3639 | 3730 |
3640 } } // namespace v8::internal | 3731 } } // namespace v8::internal |
3641 | 3732 |
3642 #endif // V8_TARGET_ARCH_ARM64 | 3733 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |