OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 if (argc == next_arg) { | 489 if (argc == next_arg) { |
490 words = 10; | 490 words = 10; |
491 } else if (argc == next_arg + 1) { | 491 } else if (argc == next_arg + 1) { |
492 if (!GetValue(argv[next_arg], &words)) { | 492 if (!GetValue(argv[next_arg], &words)) { |
493 words = 10; | 493 words = 10; |
494 } | 494 } |
495 } | 495 } |
496 end = cur + words; | 496 end = cur + words; |
497 | 497 |
498 while (cur < end) { | 498 while (cur < end) { |
499 PrintF(" 0x%08x: 0x%08x %10d\n", | 499 PrintF(" 0x%08x: 0x%08x %10d", |
500 reinterpret_cast<intptr_t>(cur), *cur, *cur); | 500 reinterpret_cast<intptr_t>(cur), *cur, *cur); |
| 501 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); |
| 502 int value = *cur; |
| 503 Heap* current_heap = v8::internal::Isolate::Current()->heap(); |
| 504 if (current_heap->Contains(obj) || ((value & 1) == 0)) { |
| 505 PrintF(" ("); |
| 506 if ((value & 1) == 0) { |
| 507 PrintF("smi %d", value / 2); |
| 508 } else { |
| 509 obj->ShortPrint(); |
| 510 } |
| 511 PrintF(")"); |
| 512 } |
| 513 PrintF("\n"); |
501 cur++; | 514 cur++; |
502 } | 515 } |
503 | 516 |
504 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) { | 517 } else if ((strcmp(cmd, "disasm") == 0) || |
| 518 (strcmp(cmd, "dpc") == 0) || |
| 519 (strcmp(cmd, "di") == 0)) { |
505 disasm::NameConverter converter; | 520 disasm::NameConverter converter; |
506 disasm::Disassembler dasm(converter); | 521 disasm::Disassembler dasm(converter); |
507 // Use a reasonably large buffer. | 522 // Use a reasonably large buffer. |
508 v8::internal::EmbeddedVector<char, 256> buffer; | 523 v8::internal::EmbeddedVector<char, 256> buffer; |
509 | 524 |
510 byte* cur = NULL; | 525 byte* cur = NULL; |
511 byte* end = NULL; | 526 byte* end = NULL; |
512 | 527 |
513 if (argc == 1) { | 528 if (argc == 1) { |
514 cur = reinterpret_cast<byte*>(sim_->get_pc()); | 529 cur = reinterpret_cast<byte*>(sim_->get_pc()); |
515 end = cur + (10 * Instruction::kInstrSize); | 530 end = cur + (10 * Instruction::kInstrSize); |
516 } else if (argc == 2) { | 531 } else if (argc == 2) { |
517 int32_t value; | 532 int regnum = Registers::Number(arg1); |
518 if (GetValue(arg1, &value)) { | 533 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { |
519 cur = reinterpret_cast<byte*>(value); | 534 // The argument is an address or a register name. |
520 // No length parameter passed, assume 10 instructions. | 535 int32_t value; |
521 end = cur + (10 * Instruction::kInstrSize); | 536 if (GetValue(arg1, &value)) { |
| 537 cur = reinterpret_cast<byte*>(value); |
| 538 // Disassemble 10 instructions at <arg1>. |
| 539 end = cur + (10 * Instruction::kInstrSize); |
| 540 } |
| 541 } else { |
| 542 // The argument is the number of instructions. |
| 543 int32_t value; |
| 544 if (GetValue(arg1, &value)) { |
| 545 cur = reinterpret_cast<byte*>(sim_->get_pc()); |
| 546 // Disassemble <arg1> instructions. |
| 547 end = cur + (value * Instruction::kInstrSize); |
| 548 } |
522 } | 549 } |
523 } else { | 550 } else { |
524 int32_t value1; | 551 int32_t value1; |
525 int32_t value2; | 552 int32_t value2; |
526 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { | 553 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { |
527 cur = reinterpret_cast<byte*>(value1); | 554 cur = reinterpret_cast<byte*>(value1); |
528 end = cur + (value2 * Instruction::kInstrSize); | 555 end = cur + (value2 * Instruction::kInstrSize); |
529 } | 556 } |
530 } | 557 } |
531 | 558 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 PrintF(" use register name 'all' to print all registers\n"); | 635 PrintF(" use register name 'all' to print all registers\n"); |
609 PrintF("printobject <register>\n"); | 636 PrintF("printobject <register>\n"); |
610 PrintF(" print an object from a register (alias 'po')\n"); | 637 PrintF(" print an object from a register (alias 'po')\n"); |
611 PrintF("stack [<words>]\n"); | 638 PrintF("stack [<words>]\n"); |
612 PrintF(" dump stack content, default dump 10 words)\n"); | 639 PrintF(" dump stack content, default dump 10 words)\n"); |
613 PrintF("mem <address> [<words>]\n"); | 640 PrintF("mem <address> [<words>]\n"); |
614 PrintF(" dump memory content, default dump 10 words)\n"); | 641 PrintF(" dump memory content, default dump 10 words)\n"); |
615 PrintF("flags\n"); | 642 PrintF("flags\n"); |
616 PrintF(" print flags\n"); | 643 PrintF(" print flags\n"); |
617 PrintF("disasm [<instructions>]\n"); | 644 PrintF("disasm [<instructions>]\n"); |
618 PrintF("disasm [[<address>] <instructions>]\n"); | 645 PrintF("disasm [<address/register>]\n"); |
619 PrintF(" disassemble code, default is 10 instructions from pc\n"); | 646 PrintF("disasm [[<address/register>] <instructions>]\n"); |
| 647 PrintF(" disassemble code, default is 10 instructions\n"); |
| 648 PrintF(" from pc (alias 'di')\n"); |
620 PrintF("gdb\n"); | 649 PrintF("gdb\n"); |
621 PrintF(" enter gdb\n"); | 650 PrintF(" enter gdb\n"); |
622 PrintF("break <address>\n"); | 651 PrintF("break <address>\n"); |
623 PrintF(" set a break point on the address\n"); | 652 PrintF(" set a break point on the address\n"); |
624 PrintF("del\n"); | 653 PrintF("del\n"); |
625 PrintF(" delete the breakpoint\n"); | 654 PrintF(" delete the breakpoint\n"); |
626 PrintF("unstop\n"); | 655 PrintF("unstop\n"); |
627 PrintF(" ignore the stop instruction at the current location"); | 656 PrintF(" ignore the stop instruction at the current location"); |
628 PrintF(" from now on\n"); | 657 PrintF(" from now on\n"); |
629 } else { | 658 } else { |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 const_cast<int32_t*>(&FPUregisters_[fpureg])); | 956 const_cast<int32_t*>(&FPUregisters_[fpureg])); |
928 } | 957 } |
929 | 958 |
930 | 959 |
931 double Simulator::get_fpu_register_double(int fpureg) const { | 960 double Simulator::get_fpu_register_double(int fpureg) const { |
932 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); | 961 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); |
933 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); | 962 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); |
934 } | 963 } |
935 | 964 |
936 | 965 |
| 966 // For use in calls that take two double values, constructed either |
| 967 // from a0-a3 or f12 and f14. |
| 968 void Simulator::GetFpArgs(double* x, double* y) { |
| 969 if (!IsMipsSoftFloatABI) { |
| 970 *x = get_fpu_register_double(12); |
| 971 *y = get_fpu_register_double(14); |
| 972 } else { |
| 973 // We use a char buffer to get around the strict-aliasing rules which |
| 974 // otherwise allow the compiler to optimize away the copy. |
| 975 char buffer[sizeof(*x)]; |
| 976 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
| 977 |
| 978 // Registers a0 and a1 -> x. |
| 979 reg_buffer[0] = get_register(a0); |
| 980 reg_buffer[1] = get_register(a1); |
| 981 memcpy(x, buffer, sizeof(buffer)); |
| 982 |
| 983 // Registers a2 and a3 -> y. |
| 984 reg_buffer[0] = get_register(a2); |
| 985 reg_buffer[1] = get_register(a3); |
| 986 memcpy(y, buffer, sizeof(buffer)); |
| 987 } |
| 988 } |
| 989 |
| 990 |
| 991 // For use in calls that take one double value, constructed either |
| 992 // from a0 and a1 or f12. |
| 993 void Simulator::GetFpArgs(double* x) { |
| 994 if (!IsMipsSoftFloatABI) { |
| 995 *x = get_fpu_register_double(12); |
| 996 } else { |
| 997 // We use a char buffer to get around the strict-aliasing rules which |
| 998 // otherwise allow the compiler to optimize away the copy. |
| 999 char buffer[sizeof(*x)]; |
| 1000 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
| 1001 // Registers a0 and a1 -> x. |
| 1002 reg_buffer[0] = get_register(a0); |
| 1003 reg_buffer[1] = get_register(a1); |
| 1004 memcpy(x, buffer, sizeof(buffer)); |
| 1005 } |
| 1006 } |
| 1007 |
| 1008 |
| 1009 // For use in calls that take one double value constructed either |
| 1010 // from a0 and a1 or f12 and one integer value. |
| 1011 void Simulator::GetFpArgs(double* x, int32_t* y) { |
| 1012 if (!IsMipsSoftFloatABI) { |
| 1013 *x = get_fpu_register_double(12); |
| 1014 *y = get_register(a2); |
| 1015 } else { |
| 1016 // We use a char buffer to get around the strict-aliasing rules which |
| 1017 // otherwise allow the compiler to optimize away the copy. |
| 1018 char buffer[sizeof(*x)]; |
| 1019 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
| 1020 // Registers 0 and 1 -> x. |
| 1021 reg_buffer[0] = get_register(a0); |
| 1022 reg_buffer[1] = get_register(a1); |
| 1023 memcpy(x, buffer, sizeof(buffer)); |
| 1024 |
| 1025 // Register 2 -> y. |
| 1026 reg_buffer[0] = get_register(a2); |
| 1027 memcpy(y, buffer, sizeof(*y)); |
| 1028 } |
| 1029 } |
| 1030 |
| 1031 |
| 1032 // The return value is either in v0/v1 or f0. |
| 1033 void Simulator::SetFpResult(const double& result) { |
| 1034 if (!IsMipsSoftFloatABI) { |
| 1035 set_fpu_register_double(0, result); |
| 1036 } else { |
| 1037 char buffer[2 * sizeof(registers_[0])]; |
| 1038 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
| 1039 memcpy(buffer, &result, sizeof(buffer)); |
| 1040 // Copy result to v0 and v1. |
| 1041 set_register(v0, reg_buffer[0]); |
| 1042 set_register(v1, reg_buffer[1]); |
| 1043 } |
| 1044 } |
| 1045 |
| 1046 |
937 // Helper functions for setting and testing the FCSR register's bits. | 1047 // Helper functions for setting and testing the FCSR register's bits. |
938 void Simulator::set_fcsr_bit(uint32_t cc, bool value) { | 1048 void Simulator::set_fcsr_bit(uint32_t cc, bool value) { |
939 if (value) { | 1049 if (value) { |
940 FCSR_ |= (1 << cc); | 1050 FCSR_ |= (1 << cc); |
941 } else { | 1051 } else { |
942 FCSR_ &= ~(1 << cc); | 1052 FCSR_ &= ~(1 << cc); |
943 } | 1053 } |
944 } | 1054 } |
945 | 1055 |
946 | 1056 |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1201 arg4 = stack_pointer[4]; | 1311 arg4 = stack_pointer[4]; |
1202 arg5 = stack_pointer[5]; | 1312 arg5 = stack_pointer[5]; |
1203 } | 1313 } |
1204 | 1314 |
1205 bool fp_call = | 1315 bool fp_call = |
1206 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || | 1316 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || |
1207 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || | 1317 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || |
1208 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || | 1318 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || |
1209 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); | 1319 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); |
1210 | 1320 |
| 1321 if (!IsMipsSoftFloatABI) { |
| 1322 // With the hard floating point calling convention, double |
| 1323 // arguments are passed in FPU registers. Fetch the arguments |
| 1324 // from there and call the builtin using soft floating point |
| 1325 // convention. |
| 1326 switch (redirection->type()) { |
| 1327 case ExternalReference::BUILTIN_FP_FP_CALL: |
| 1328 case ExternalReference::BUILTIN_COMPARE_CALL: |
| 1329 arg0 = get_fpu_register(f12); |
| 1330 arg1 = get_fpu_register(f13); |
| 1331 arg2 = get_fpu_register(f14); |
| 1332 arg3 = get_fpu_register(f15); |
| 1333 break; |
| 1334 case ExternalReference::BUILTIN_FP_CALL: |
| 1335 arg0 = get_fpu_register(f12); |
| 1336 arg1 = get_fpu_register(f13); |
| 1337 break; |
| 1338 case ExternalReference::BUILTIN_FP_INT_CALL: |
| 1339 arg0 = get_fpu_register(f12); |
| 1340 arg1 = get_fpu_register(f13); |
| 1341 arg2 = get_register(a2); |
| 1342 break; |
| 1343 default: |
| 1344 break; |
| 1345 } |
| 1346 } |
| 1347 |
1211 // This is dodgy but it works because the C entry stubs are never moved. | 1348 // This is dodgy but it works because the C entry stubs are never moved. |
1212 // See comment in codegen-arm.cc and bug 1242173. | 1349 // See comment in codegen-arm.cc and bug 1242173. |
1213 int32_t saved_ra = get_register(ra); | 1350 int32_t saved_ra = get_register(ra); |
1214 | 1351 |
1215 intptr_t external = | 1352 intptr_t external = |
1216 reinterpret_cast<intptr_t>(redirection->external_function()); | 1353 reinterpret_cast<intptr_t>(redirection->external_function()); |
1217 | 1354 |
1218 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware | 1355 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware |
1219 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this | 1356 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this |
1220 // simulator. Soft-float has additional abstraction of ExternalReference, | 1357 // simulator. Soft-float has additional abstraction of ExternalReference, |
1221 // to support serialization. Finally, when simulated on x86 host, the | 1358 // to support serialization. |
1222 // x86 softfloat routines are used, and this Redirection infrastructure | |
1223 // lets simulated-mips make calls into x86 C code. | |
1224 // When doing that, the 'double' return type must be handled differently | |
1225 // than the usual int64_t return. The data is returned in different | |
1226 // registers and cannot be cast from one type to the other. However, the | |
1227 // calling arguments are passed the same way in both cases. | |
1228 if (fp_call) { | 1359 if (fp_call) { |
1229 SimulatorRuntimeFPCall target = | 1360 SimulatorRuntimeFPCall target = |
1230 reinterpret_cast<SimulatorRuntimeFPCall>(external); | 1361 reinterpret_cast<SimulatorRuntimeFPCall>(external); |
1231 if (::v8::internal::FLAG_trace_sim) { | 1362 if (::v8::internal::FLAG_trace_sim) { |
1232 PrintF( | 1363 double dval0, dval1; |
1233 "Call to host function at %p args %08x, %08x, %08x, %08x\n", | 1364 int32_t ival; |
1234 FUNCTION_ADDR(target), | 1365 switch (redirection->type()) { |
1235 arg0, | 1366 case ExternalReference::BUILTIN_FP_FP_CALL: |
1236 arg1, | 1367 case ExternalReference::BUILTIN_COMPARE_CALL: |
1237 arg2, | 1368 GetFpArgs(&dval0, &dval1); |
1238 arg3); | 1369 PrintF("Call to host function at %p with args %f, %f", |
1239 } | 1370 FUNCTION_ADDR(target), dval0, dval1); |
| 1371 break; |
| 1372 case ExternalReference::BUILTIN_FP_CALL: |
| 1373 GetFpArgs(&dval0); |
| 1374 PrintF("Call to host function at %p with arg %f", |
| 1375 FUNCTION_ADDR(target), dval1); |
| 1376 break; |
| 1377 case ExternalReference::BUILTIN_FP_INT_CALL: |
| 1378 GetFpArgs(&dval0, &ival); |
| 1379 PrintF("Call to host function at %p with args %f, %d", |
| 1380 FUNCTION_ADDR(target), dval0, ival); |
| 1381 break; |
| 1382 default: |
| 1383 UNREACHABLE(); |
| 1384 break; |
| 1385 } |
| 1386 } |
1240 double result = target(arg0, arg1, arg2, arg3); | 1387 double result = target(arg0, arg1, arg2, arg3); |
1241 // fp result -> registers v0 and v1. | 1388 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { |
1242 int32_t gpreg_pair[2]; | 1389 SetFpResult(result); |
1243 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); | 1390 } else { |
1244 set_register(v0, gpreg_pair[0]); | 1391 int32_t gpreg_pair[2]; |
1245 set_register(v1, gpreg_pair[1]); | 1392 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); |
| 1393 set_register(v0, gpreg_pair[0]); |
| 1394 set_register(v1, gpreg_pair[1]); |
| 1395 } |
1246 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { | 1396 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { |
1247 // See DirectCEntryStub::GenerateCall for explanation of register usage. | 1397 // See DirectCEntryStub::GenerateCall for explanation of register usage. |
1248 SimulatorRuntimeDirectApiCall target = | 1398 SimulatorRuntimeDirectApiCall target = |
1249 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); | 1399 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); |
1250 if (::v8::internal::FLAG_trace_sim) { | 1400 if (::v8::internal::FLAG_trace_sim) { |
1251 PrintF("Call to host function at %p args %08x\n", | 1401 PrintF("Call to host function at %p args %08x\n", |
1252 FUNCTION_ADDR(target), arg1); | 1402 FUNCTION_ADDR(target), arg1); |
1253 } | 1403 } |
1254 v8::Handle<v8::Value> result = target(arg1); | 1404 v8::Handle<v8::Value> result = target(arg1); |
1255 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result; | 1405 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result; |
(...skipping 1206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2462 } | 2612 } |
2463 | 2613 |
2464 | 2614 |
2465 #undef UNSUPPORTED | 2615 #undef UNSUPPORTED |
2466 | 2616 |
2467 } } // namespace v8::internal | 2617 } } // namespace v8::internal |
2468 | 2618 |
2469 #endif // USE_SIMULATOR | 2619 #endif // USE_SIMULATOR |
2470 | 2620 |
2471 #endif // V8_TARGET_ARCH_MIPS | 2621 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |