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

Unified Diff: src/arm64/simulator-arm64.cc

Issue 268353005: ARM64: Fix and improve MacroAssembler::Printf. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Reorganise Simulator::DoPrintf as suggested. Created 6 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/arm64/simulator-arm64.h ('k') | test/cctest/test-assembler-arm64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm64/simulator-arm64.cc
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
index 3c970f854a07a6f2bb64ca186d074b7a4cce981c..c7c9f6cedd9105aef766f45f273dfcf8226d9fc1 100644
--- a/src/arm64/simulator-arm64.cc
+++ b/src/arm64/simulator-arm64.cc
@@ -3581,43 +3581,7 @@ void Simulator::VisitException(Instruction* instr) {
} else if (instr->ImmException() == kImmExceptionIsRedirectedCall) {
DoRuntimeCall(instr);
} else if (instr->ImmException() == kImmExceptionIsPrintf) {
- // Read the argument encoded inline in the instruction stream.
- uint32_t type;
- memcpy(&type,
- pc_->InstructionAtOffset(kPrintfTypeOffset),
- sizeof(type));
-
- const char* format = reg<const char*>(0);
-
- // Pass all of the relevant PCS registers onto printf. It doesn't
- // matter if we pass too many as the extra ones won't be read.
- int result;
- fputs(clr_printf, stream_);
- if (type == CPURegister::kRegister) {
- result = fprintf(stream_, format,
- xreg(1), xreg(2), xreg(3), xreg(4),
- xreg(5), xreg(6), xreg(7));
- } else if (type == CPURegister::kFPRegister) {
- result = fprintf(stream_, format,
- dreg(0), dreg(1), dreg(2), dreg(3),
- dreg(4), dreg(5), dreg(6), dreg(7));
- } else {
- ASSERT(type == CPURegister::kNoRegister);
- result = fprintf(stream_, "%s", format);
- }
- fputs(clr_normal, stream_);
-
-#ifdef DEBUG
- CorruptAllCallerSavedCPURegisters();
-#endif
-
- set_xreg(0, result);
-
- // The printf parameters are inlined in the code, so skip them.
- set_pc(pc_->InstructionAtOffset(kPrintfLength));
-
- // Set LR as if we'd just called a native printf function.
- set_lr(pc());
+ DoPrintf(instr);
} else if (instr->ImmException() == kImmExceptionIsUnreachable) {
fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n",
@@ -3635,6 +3599,133 @@ void Simulator::VisitException(Instruction* instr) {
}
}
+
+void Simulator::DoPrintf(Instruction* instr) {
+ ASSERT((instr->Mask(ExceptionMask) == HLT) &&
+ (instr->ImmException() == kImmExceptionIsPrintf));
+
+ // Read the arguments encoded inline in the instruction stream.
+ uint32_t arg_count;
+ uint32_t arg_pattern_list;
+ STATIC_ASSERT(sizeof(*instr) == 1);
+ memcpy(&arg_count,
+ instr + kPrintfArgCountOffset,
+ sizeof(arg_count));
+ memcpy(&arg_pattern_list,
+ instr + kPrintfArgPatternListOffset,
+ sizeof(arg_pattern_list));
+
+ ASSERT(arg_count <= kPrintfMaxArgCount);
+ ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
+
+ // We need to call the host printf function with a set of arguments defined by
+ // arg_pattern_list. Because we don't know the types and sizes of the
+ // arguments, this is very difficult to do in a robust and portable way. To
+ // work around the problem, we pick apart the format string, and print one
+ // format placeholder at a time.
+
+ // Allocate space for the format string. We take a copy, so we can modify it.
+ // Leave enough space for one extra character per expected argument (plus the
+ // '\0' termination).
+ const char * format_base = reg<const char *>(0);
+ ASSERT(format_base != NULL);
+ size_t length = strlen(format_base) + 1;
+ char * const format = new char[length + arg_count];
+
+ // A list of chunks, each with exactly one format placeholder.
+ const char * chunks[kPrintfMaxArgCount];
+
+ // Copy the format string and search for format placeholders.
+ uint32_t placeholder_count = 0;
+ char * format_scratch = format;
+ for (size_t i = 0; i < length; i++) {
+ if (format_base[i] != '%') {
+ *format_scratch++ = format_base[i];
+ } else {
+ if (format_base[i + 1] == '%') {
+ // Ignore explicit "%%" sequences.
+ *format_scratch++ = format_base[i];
+
+ if (placeholder_count == 0) {
+ // The first chunk is passed to printf using "%s", so we need to
+ // unescape "%%" sequences in this chunk. (Just skip the next '%'.)
+ i++;
+ } else {
+ // Otherwise, pass through "%%" unchanged.
+ *format_scratch++ = format_base[++i];
+ }
+ } else {
+ CHECK(placeholder_count < arg_count);
+ // Insert '\0' before placeholders, and store their locations.
+ *format_scratch++ = '\0';
+ chunks[placeholder_count++] = format_scratch;
+ *format_scratch++ = format_base[i];
+ }
+ }
+ }
+ ASSERT(format_scratch <= (format + length + arg_count));
+ CHECK(placeholder_count == arg_count);
+
+ // Finally, call printf with each chunk, passing the appropriate register
+ // argument. Normally, printf returns the number of bytes transmitted, so we
+ // can emulate a single printf call by adding the result from each chunk. If
+ // any call returns a negative (error) value, though, just return that value.
+
+ fprintf(stream_, "%s", clr_printf);
+
+ // Because '\0' is inserted before each placeholder, the first string in
+ // 'format' contains no format placeholders and should be printed literally.
+ int result = fprintf(stream_, "%s", format);
+ int pcs_r = 1; // Start at x1. x0 holds the format string.
+ int pcs_f = 0; // Start at d0.
+ if (result >= 0) {
+ for (uint32_t i = 0; i < placeholder_count; i++) {
+ int part_result = -1;
+
+ uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
+ arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
+ switch (arg_pattern) {
+ case kPrintfArgW:
+ part_result = fprintf(stream_, chunks[i], wreg(pcs_r++));
+ break;
+ case kPrintfArgX:
+ part_result = fprintf(stream_, chunks[i], xreg(pcs_r++));
+ break;
+ case kPrintfArgD:
+ part_result = fprintf(stream_, chunks[i], dreg(pcs_f++));
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (part_result < 0) {
+ // Handle error values.
+ result = part_result;
+ break;
+ }
+
+ result += part_result;
+ }
+ }
+
+ fprintf(stream_, "%s", clr_normal);
+
+#ifdef DEBUG
+ CorruptAllCallerSavedCPURegisters();
+#endif
+
+ // Printf returns its result in x0 (just like the C library's printf).
+ set_xreg(0, result);
+
+ // The printf parameters are inlined in the code, so skip them.
+ set_pc(instr->InstructionAtOffset(kPrintfLength));
+
+ // Set LR as if we'd just called a native printf function.
+ set_lr(pc());
+
+ delete[] format;
+}
+
+
#endif // USE_SIMULATOR
} } // namespace v8::internal
« no previous file with comments | « src/arm64/simulator-arm64.h ('k') | test/cctest/test-assembler-arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698