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 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 const_cast<int32_t*>(&FPUregisters_[fpureg])); | 1084 const_cast<int32_t*>(&FPUregisters_[fpureg])); |
1085 } | 1085 } |
1086 | 1086 |
1087 | 1087 |
1088 double Simulator::get_fpu_register_double(int fpureg) const { | 1088 double Simulator::get_fpu_register_double(int fpureg) const { |
1089 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); | 1089 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); |
1090 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); | 1090 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); |
1091 } | 1091 } |
1092 | 1092 |
1093 | 1093 |
1094 // For use in calls that take two double values, constructed either | 1094 // Runtime FP routines take up to two double arguments and zero |
| 1095 // or one integer arguments. All are constructed here, |
1095 // from a0-a3 or f12 and f14. | 1096 // from a0-a3 or f12 and f14. |
1096 void Simulator::GetFpArgs(double* x, double* y) { | 1097 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) { |
1097 if (!IsMipsSoftFloatABI) { | 1098 if (!IsMipsSoftFloatABI) { |
1098 *x = get_fpu_register_double(12); | 1099 *x = get_fpu_register_double(12); |
1099 *y = get_fpu_register_double(14); | 1100 *y = get_fpu_register_double(14); |
| 1101 *z = get_register(a2); |
1100 } else { | 1102 } else { |
1101 // We use a char buffer to get around the strict-aliasing rules which | 1103 // We use a char buffer to get around the strict-aliasing rules which |
1102 // otherwise allow the compiler to optimize away the copy. | 1104 // otherwise allow the compiler to optimize away the copy. |
1103 char buffer[sizeof(*x)]; | 1105 char buffer[sizeof(*x)]; |
1104 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); | 1106 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
1105 | 1107 |
1106 // Registers a0 and a1 -> x. | 1108 // Registers a0 and a1 -> x. |
1107 reg_buffer[0] = get_register(a0); | 1109 reg_buffer[0] = get_register(a0); |
1108 reg_buffer[1] = get_register(a1); | 1110 reg_buffer[1] = get_register(a1); |
1109 memcpy(x, buffer, sizeof(buffer)); | 1111 memcpy(x, buffer, sizeof(buffer)); |
1110 | |
1111 // Registers a2 and a3 -> y. | 1112 // Registers a2 and a3 -> y. |
1112 reg_buffer[0] = get_register(a2); | 1113 reg_buffer[0] = get_register(a2); |
1113 reg_buffer[1] = get_register(a3); | 1114 reg_buffer[1] = get_register(a3); |
1114 memcpy(y, buffer, sizeof(buffer)); | 1115 memcpy(y, buffer, sizeof(buffer)); |
| 1116 // Register 2 -> z. |
| 1117 reg_buffer[0] = get_register(a2); |
| 1118 memcpy(z, buffer, sizeof(*z)); |
1115 } | 1119 } |
1116 } | 1120 } |
1117 | 1121 |
1118 | |
1119 // For use in calls that take one double value, constructed either | |
1120 // from a0 and a1 or f12. | |
1121 void Simulator::GetFpArgs(double* x) { | |
1122 if (!IsMipsSoftFloatABI) { | |
1123 *x = get_fpu_register_double(12); | |
1124 } else { | |
1125 // We use a char buffer to get around the strict-aliasing rules which | |
1126 // otherwise allow the compiler to optimize away the copy. | |
1127 char buffer[sizeof(*x)]; | |
1128 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); | |
1129 // Registers a0 and a1 -> x. | |
1130 reg_buffer[0] = get_register(a0); | |
1131 reg_buffer[1] = get_register(a1); | |
1132 memcpy(x, buffer, sizeof(buffer)); | |
1133 } | |
1134 } | |
1135 | |
1136 | |
1137 // For use in calls that take one double value constructed either | |
1138 // from a0 and a1 or f12 and one integer value. | |
1139 void Simulator::GetFpArgs(double* x, int32_t* y) { | |
1140 if (!IsMipsSoftFloatABI) { | |
1141 *x = get_fpu_register_double(12); | |
1142 *y = get_register(a2); | |
1143 } else { | |
1144 // We use a char buffer to get around the strict-aliasing rules which | |
1145 // otherwise allow the compiler to optimize away the copy. | |
1146 char buffer[sizeof(*x)]; | |
1147 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); | |
1148 // Registers 0 and 1 -> x. | |
1149 reg_buffer[0] = get_register(a0); | |
1150 reg_buffer[1] = get_register(a1); | |
1151 memcpy(x, buffer, sizeof(buffer)); | |
1152 | |
1153 // Register 2 -> y. | |
1154 reg_buffer[0] = get_register(a2); | |
1155 memcpy(y, buffer, sizeof(*y)); | |
1156 } | |
1157 } | |
1158 | |
1159 | 1122 |
1160 // The return value is either in v0/v1 or f0. | 1123 // The return value is either in v0/v1 or f0. |
1161 void Simulator::SetFpResult(const double& result) { | 1124 void Simulator::SetFpResult(const double& result) { |
1162 if (!IsMipsSoftFloatABI) { | 1125 if (!IsMipsSoftFloatABI) { |
1163 set_fpu_register_double(0, result); | 1126 set_fpu_register_double(0, result); |
1164 } else { | 1127 } else { |
1165 char buffer[2 * sizeof(registers_[0])]; | 1128 char buffer[2 * sizeof(registers_[0])]; |
1166 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); | 1129 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
1167 memcpy(buffer, &result, sizeof(buffer)); | 1130 memcpy(buffer, &result, sizeof(buffer)); |
1168 // Copy result to v0 and v1. | 1131 // Copy result to v0 and v1. |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1408 // uses the ObjectPair which is essentially two 32-bit values stuffed into a | 1371 // uses the ObjectPair which is essentially two 32-bit values stuffed into a |
1409 // 64-bit value. With the code below we assume that all runtime calls return | 1372 // 64-bit value. With the code below we assume that all runtime calls return |
1410 // 64 bits of result. If they don't, the v1 result register contains a bogus | 1373 // 64 bits of result. If they don't, the v1 result register contains a bogus |
1411 // value, which is fine because it is caller-saved. | 1374 // value, which is fine because it is caller-saved. |
1412 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, | 1375 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, |
1413 int32_t arg1, | 1376 int32_t arg1, |
1414 int32_t arg2, | 1377 int32_t arg2, |
1415 int32_t arg3, | 1378 int32_t arg3, |
1416 int32_t arg4, | 1379 int32_t arg4, |
1417 int32_t arg5); | 1380 int32_t arg5); |
1418 typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, | 1381 |
1419 int32_t arg1, | 1382 // These prototypes handle the four types of FP calls. |
1420 int32_t arg2, | 1383 typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1); |
1421 int32_t arg3); | 1384 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1); |
| 1385 typedef double (*SimulatorRuntimeFPCall)(double darg0); |
| 1386 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0); |
1422 | 1387 |
1423 // This signature supports direct call in to API function native callback | 1388 // This signature supports direct call in to API function native callback |
1424 // (refer to InvocationCallback in v8.h). | 1389 // (refer to InvocationCallback in v8.h). |
1425 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0); | 1390 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0); |
1426 | 1391 |
1427 // This signature supports direct call to accessor getter callback. | 1392 // This signature supports direct call to accessor getter callback. |
1428 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, | 1393 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, |
1429 int32_t arg1); | 1394 int32_t arg1); |
1430 | 1395 |
1431 // Software interrupt instructions are used by the simulator to call into the | 1396 // Software interrupt instructions are used by the simulator to call into the |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1488 int32_t saved_ra = get_register(ra); | 1453 int32_t saved_ra = get_register(ra); |
1489 | 1454 |
1490 intptr_t external = | 1455 intptr_t external = |
1491 reinterpret_cast<intptr_t>(redirection->external_function()); | 1456 reinterpret_cast<intptr_t>(redirection->external_function()); |
1492 | 1457 |
1493 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware | 1458 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware |
1494 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this | 1459 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this |
1495 // simulator. Soft-float has additional abstraction of ExternalReference, | 1460 // simulator. Soft-float has additional abstraction of ExternalReference, |
1496 // to support serialization. | 1461 // to support serialization. |
1497 if (fp_call) { | 1462 if (fp_call) { |
1498 SimulatorRuntimeFPCall target = | 1463 double dval0, dval1; // one or two double parameters |
1499 reinterpret_cast<SimulatorRuntimeFPCall>(external); | 1464 int32_t ival; // zero or one integer parameters |
| 1465 int64_t iresult = 0; // integer return value |
| 1466 double dresult = 0; // double return value |
| 1467 GetFpArgs(&dval0, &dval1, &ival); |
| 1468 SimulatorRuntimeCall generic_target = |
| 1469 reinterpret_cast<SimulatorRuntimeCall>(external); |
1500 if (::v8::internal::FLAG_trace_sim) { | 1470 if (::v8::internal::FLAG_trace_sim) { |
1501 double dval0, dval1; | |
1502 int32_t ival; | |
1503 switch (redirection->type()) { | 1471 switch (redirection->type()) { |
1504 case ExternalReference::BUILTIN_FP_FP_CALL: | 1472 case ExternalReference::BUILTIN_FP_FP_CALL: |
1505 case ExternalReference::BUILTIN_COMPARE_CALL: | 1473 case ExternalReference::BUILTIN_COMPARE_CALL: |
1506 GetFpArgs(&dval0, &dval1); | |
1507 PrintF("Call to host function at %p with args %f, %f", | 1474 PrintF("Call to host function at %p with args %f, %f", |
1508 FUNCTION_ADDR(target), dval0, dval1); | 1475 FUNCTION_ADDR(generic_target), dval0, dval1); |
1509 break; | 1476 break; |
1510 case ExternalReference::BUILTIN_FP_CALL: | 1477 case ExternalReference::BUILTIN_FP_CALL: |
1511 GetFpArgs(&dval0); | |
1512 PrintF("Call to host function at %p with arg %f", | 1478 PrintF("Call to host function at %p with arg %f", |
1513 FUNCTION_ADDR(target), dval0); | 1479 FUNCTION_ADDR(generic_target), dval0); |
1514 break; | 1480 break; |
1515 case ExternalReference::BUILTIN_FP_INT_CALL: | 1481 case ExternalReference::BUILTIN_FP_INT_CALL: |
1516 GetFpArgs(&dval0, &ival); | |
1517 PrintF("Call to host function at %p with args %f, %d", | 1482 PrintF("Call to host function at %p with args %f, %d", |
1518 FUNCTION_ADDR(target), dval0, ival); | 1483 FUNCTION_ADDR(generic_target), dval0, ival); |
1519 break; | 1484 break; |
1520 default: | 1485 default: |
1521 UNREACHABLE(); | 1486 UNREACHABLE(); |
1522 break; | 1487 break; |
1523 } | 1488 } |
1524 } | 1489 } |
1525 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { | 1490 switch (redirection->type()) { |
| 1491 case ExternalReference::BUILTIN_COMPARE_CALL: { |
| 1492 SimulatorRuntimeCompareCall target = |
| 1493 reinterpret_cast<SimulatorRuntimeCompareCall>(external); |
| 1494 iresult = target(dval0, dval1); |
| 1495 set_register(v0, static_cast<int32_t>(iresult)); |
| 1496 set_register(v1, static_cast<int32_t>(iresult >> 32)); |
| 1497 break; |
| 1498 } |
| 1499 case ExternalReference::BUILTIN_FP_FP_CALL: { |
| 1500 SimulatorRuntimeFPFPCall target = |
| 1501 reinterpret_cast<SimulatorRuntimeFPFPCall>(external); |
| 1502 dresult = target(dval0, dval1); |
| 1503 SetFpResult(dresult); |
| 1504 break; |
| 1505 } |
| 1506 case ExternalReference::BUILTIN_FP_CALL: { |
1526 SimulatorRuntimeFPCall target = | 1507 SimulatorRuntimeFPCall target = |
1527 reinterpret_cast<SimulatorRuntimeFPCall>(external); | 1508 reinterpret_cast<SimulatorRuntimeFPCall>(external); |
1528 double result = target(arg0, arg1, arg2, arg3); | 1509 dresult = target(dval0); |
1529 SetFpResult(result); | 1510 SetFpResult(dresult); |
1530 } else { | 1511 break; |
1531 SimulatorRuntimeCall target = | 1512 } |
1532 reinterpret_cast<SimulatorRuntimeCall>(external); | 1513 case ExternalReference::BUILTIN_FP_INT_CALL: { |
1533 uint64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); | 1514 SimulatorRuntimeFPIntCall target = |
1534 int32_t gpreg_pair[2]; | 1515 reinterpret_cast<SimulatorRuntimeFPIntCall>(external); |
1535 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); | 1516 dresult = target(dval0, ival); |
1536 set_register(v0, gpreg_pair[0]); | 1517 SetFpResult(dresult); |
1537 set_register(v1, gpreg_pair[1]); | 1518 break; |
| 1519 } |
| 1520 default: |
| 1521 UNREACHABLE(); |
| 1522 break; |
| 1523 } |
| 1524 if (::v8::internal::FLAG_trace_sim) { |
| 1525 switch (redirection->type()) { |
| 1526 case ExternalReference::BUILTIN_COMPARE_CALL: |
| 1527 PrintF("Returned %08x\n", static_cast<int32_t>(iresult)); |
| 1528 break; |
| 1529 case ExternalReference::BUILTIN_FP_FP_CALL: |
| 1530 case ExternalReference::BUILTIN_FP_CALL: |
| 1531 case ExternalReference::BUILTIN_FP_INT_CALL: |
| 1532 PrintF("Returned %f\n", dresult); |
| 1533 break; |
| 1534 default: |
| 1535 UNREACHABLE(); |
| 1536 break; |
| 1537 } |
1538 } | 1538 } |
1539 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { | 1539 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { |
1540 // See DirectCEntryStub::GenerateCall for explanation of register usage. | 1540 // See DirectCEntryStub::GenerateCall for explanation of register usage. |
1541 SimulatorRuntimeDirectApiCall target = | 1541 SimulatorRuntimeDirectApiCall target = |
1542 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); | 1542 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); |
1543 if (::v8::internal::FLAG_trace_sim) { | 1543 if (::v8::internal::FLAG_trace_sim) { |
1544 PrintF("Call to host function at %p args %08x\n", | 1544 PrintF("Call to host function at %p args %08x\n", |
1545 FUNCTION_ADDR(target), arg1); | 1545 FUNCTION_ADDR(target), arg1); |
1546 } | 1546 } |
1547 v8::Handle<v8::Value> result = target(arg1); | 1547 v8::Handle<v8::Value> result = target(arg1); |
(...skipping 1351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2899 } | 2899 } |
2900 | 2900 |
2901 | 2901 |
2902 #undef UNSUPPORTED | 2902 #undef UNSUPPORTED |
2903 | 2903 |
2904 } } // namespace v8::internal | 2904 } } // namespace v8::internal |
2905 | 2905 |
2906 #endif // USE_SIMULATOR | 2906 #endif // USE_SIMULATOR |
2907 | 2907 |
2908 #endif // V8_TARGET_ARCH_MIPS | 2908 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |