summaryrefslogtreecommitdiff
path: root/deps/v8/src/execution/arm64/simulator-arm64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/execution/arm64/simulator-arm64.cc')
-rw-r--r--deps/v8/src/execution/arm64/simulator-arm64.cc130
1 files changed, 93 insertions, 37 deletions
diff --git a/deps/v8/src/execution/arm64/simulator-arm64.cc b/deps/v8/src/execution/arm64/simulator-arm64.cc
index 71fedd5b2f..d3a73cbad8 100644
--- a/deps/v8/src/execution/arm64/simulator-arm64.cc
+++ b/deps/v8/src/execution/arm64/simulator-arm64.cc
@@ -12,6 +12,7 @@
#include <type_traits>
#include "src/base/lazy-instance.h"
+#include "src/base/overflowing-math.h"
#include "src/codegen/arm64/decoder-arm64-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
@@ -154,6 +155,22 @@ void Simulator::CallImpl(Address entry, CallArgument* args) {
set_sp(original_stack);
}
+#ifdef DEBUG
+namespace {
+int PopLowestIndexAsCode(CPURegList* list) {
+ if (list->IsEmpty()) {
+ return -1;
+ }
+ RegList reg_list = list->list();
+ int index = base::bits::CountTrailingZeros(reg_list);
+ DCHECK((1LL << index) & reg_list);
+ list->Remove(index);
+
+ return index;
+}
+} // namespace
+#endif
+
void Simulator::CheckPCSComplianceAndRun() {
// Adjust JS-based stack limit to C-based stack limit.
isolate_->stack_guard()->AdjustStackLimitForSimulator();
@@ -171,10 +188,10 @@ void Simulator::CheckPCSComplianceAndRun() {
for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
// x31 is not a caller saved register, so no need to specify if we want
// the stack or zero.
- saved_registers[i] = xreg(register_list.PopLowestIndex().code());
+ saved_registers[i] = xreg(PopLowestIndexAsCode(&register_list));
}
for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
- saved_fpregisters[i] = dreg_bits(fpregister_list.PopLowestIndex().code());
+ saved_fpregisters[i] = dreg_bits(PopLowestIndexAsCode(&fpregister_list));
}
int64_t original_stack = sp();
#endif
@@ -186,11 +203,11 @@ void Simulator::CheckPCSComplianceAndRun() {
register_list = kCalleeSaved;
fpregister_list = kCalleeSavedV;
for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
- DCHECK_EQ(saved_registers[i], xreg(register_list.PopLowestIndex().code()));
+ DCHECK_EQ(saved_registers[i], xreg(PopLowestIndexAsCode(&register_list)));
}
for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
DCHECK(saved_fpregisters[i] ==
- dreg_bits(fpregister_list.PopLowestIndex().code()));
+ dreg_bits(PopLowestIndexAsCode(&fpregister_list)));
}
// Corrupt caller saved register minus the return regiters.
@@ -217,13 +234,13 @@ void Simulator::CheckPCSComplianceAndRun() {
void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) {
if (list->type() == CPURegister::kRegister) {
while (!list->IsEmpty()) {
- unsigned code = list->PopLowestIndex().code();
+ unsigned code = PopLowestIndexAsCode(list);
set_xreg(code, value | code);
}
} else {
DCHECK_EQ(list->type(), CPURegister::kVRegister);
while (!list->IsEmpty()) {
- unsigned code = list->PopLowestIndex().code();
+ unsigned code = PopLowestIndexAsCode(list);
set_dreg_bits(code, value | code);
}
}
@@ -414,6 +431,34 @@ using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1);
using SimulatorRuntimeProfilingGetterCall = void (*)(int64_t arg0, int64_t arg1,
void* arg2);
+// Separate for fine-grained UBSan blacklisting. Casting any given C++
+// function to {SimulatorRuntimeCall} is undefined behavior; but since
+// the target function can indeed be any function that's exposed via
+// the "fast C call" mechanism, we can't reconstruct its signature here.
+ObjectPair UnsafeGenericFunctionCall(int64_t function, int64_t arg0,
+ int64_t arg1, int64_t arg2, int64_t arg3,
+ int64_t arg4, int64_t arg5, int64_t arg6,
+ int64_t arg7, int64_t arg8, int64_t arg9) {
+ SimulatorRuntimeCall target =
+ reinterpret_cast<SimulatorRuntimeCall>(function);
+ return target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+}
+void UnsafeDirectApiCall(int64_t function, int64_t arg0) {
+ SimulatorRuntimeDirectApiCall target =
+ reinterpret_cast<SimulatorRuntimeDirectApiCall>(function);
+ target(arg0);
+}
+void UnsafeProfilingApiCall(int64_t function, int64_t arg0, void* arg1) {
+ SimulatorRuntimeProfilingApiCall target =
+ reinterpret_cast<SimulatorRuntimeProfilingApiCall>(function);
+ target(arg0, arg1);
+}
+void UnsafeDirectGetterCall(int64_t function, int64_t arg0, int64_t arg1) {
+ SimulatorRuntimeDirectGetterCall target =
+ reinterpret_cast<SimulatorRuntimeDirectGetterCall>(function);
+ target(arg0, arg1);
+}
+
void Simulator::DoRuntimeCall(Instruction* instr) {
Redirection* redirection = Redirection::FromInstruction(instr);
@@ -515,10 +560,8 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
", "
"0x%016" PRIx64 ", 0x%016" PRIx64,
arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
- SimulatorRuntimeCall target =
- reinterpret_cast<SimulatorRuntimeCall>(external);
- ObjectPair result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+ ObjectPair result = UnsafeGenericFunctionCall(
+ external, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
TraceSim("Returned: {%p, %p}\n", reinterpret_cast<void*>(result.x),
reinterpret_cast<void*>(result.y));
#ifdef DEBUG
@@ -532,10 +575,8 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
case ExternalReference::DIRECT_API_CALL: {
// void f(v8::FunctionCallbackInfo&)
TraceSim("Type: DIRECT_API_CALL\n");
- SimulatorRuntimeDirectApiCall target =
- reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0));
- target(xreg(0));
+ UnsafeDirectApiCall(external, xreg(0));
TraceSim("No return value.");
#ifdef DEBUG
CorruptAllCallerSavedCPURegisters();
@@ -606,11 +647,9 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
case ExternalReference::DIRECT_GETTER_CALL: {
// void f(Local<String> property, PropertyCallbackInfo& info)
TraceSim("Type: DIRECT_GETTER_CALL\n");
- SimulatorRuntimeDirectGetterCall target =
- reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n", xreg(0),
xreg(1));
- target(xreg(0), xreg(1));
+ UnsafeDirectGetterCall(external, xreg(0), xreg(1));
TraceSim("No return value.");
#ifdef DEBUG
CorruptAllCallerSavedCPURegisters();
@@ -621,11 +660,9 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
case ExternalReference::PROFILING_API_CALL: {
// void f(v8::FunctionCallbackInfo&, v8::FunctionCallback)
TraceSim("Type: PROFILING_API_CALL\n");
- SimulatorRuntimeProfilingApiCall target =
- reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
void* arg1 = Redirection::ReverseRedirection(xreg(1));
TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1);
- target(xreg(0), arg1);
+ UnsafeProfilingApiCall(external, xreg(0), arg1);
TraceSim("No return value.");
#ifdef DEBUG
CorruptAllCallerSavedCPURegisters();
@@ -849,10 +886,12 @@ T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
if (amount == 0) {
return value;
}
+ // Larger shift {amount}s would be undefined behavior in C++.
+ DCHECK(amount < sizeof(value) * kBitsPerByte);
switch (shift_type) {
case LSL:
- return value << amount;
+ return static_cast<unsignedT>(value) << amount;
case LSR:
return static_cast<unsignedT>(value) >> amount;
case ASR:
@@ -873,6 +912,7 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8;
const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8;
const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;
+ using unsignedT = typename std::make_unsigned<T>::type;
switch (extend_type) {
case UXTB:
@@ -885,13 +925,19 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
value &= kWordMask;
break;
case SXTB:
- value = (value << kSignExtendBShift) >> kSignExtendBShift;
+ value =
+ static_cast<T>(static_cast<unsignedT>(value) << kSignExtendBShift) >>
+ kSignExtendBShift;
break;
case SXTH:
- value = (value << kSignExtendHShift) >> kSignExtendHShift;
+ value =
+ static_cast<T>(static_cast<unsignedT>(value) << kSignExtendHShift) >>
+ kSignExtendHShift;
break;
case SXTW:
- value = (value << kSignExtendWShift) >> kSignExtendWShift;
+ value =
+ static_cast<T>(static_cast<unsignedT>(value) << kSignExtendWShift) >>
+ kSignExtendWShift;
break;
case UXTX:
case SXTX:
@@ -899,7 +945,7 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
default:
UNREACHABLE();
}
- return value << left_shift;
+ return static_cast<T>(static_cast<unsignedT>(value) << left_shift);
}
template <typename T>
@@ -2283,7 +2329,9 @@ void Simulator::VisitConditionalSelect(Instruction* instr) {
break;
case CSNEG_w:
case CSNEG_x:
- new_val = (uint64_t)(-(int64_t)new_val);
+ // Simulate two's complement (instead of casting to signed and negating)
+ // to avoid undefined behavior on signed overflow.
+ new_val = (~new_val) + 1;
break;
default:
UNIMPLEMENTED();
@@ -2446,23 +2494,27 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) {
switch (instr->Mask(DataProcessing3SourceMask)) {
case MADD_w:
case MADD_x:
- result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
+ result = base::AddWithWraparound(
+ xreg(instr->Ra()),
+ base::MulWithWraparound(xreg(instr->Rn()), xreg(instr->Rm())));
break;
case MSUB_w:
case MSUB_x:
- result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
+ result = base::SubWithWraparound(
+ xreg(instr->Ra()),
+ base::MulWithWraparound(xreg(instr->Rn()), xreg(instr->Rm())));
break;
case SMADDL_x:
- result = xreg(instr->Ra()) + (rn_s32 * rm_s32);
+ result = base::AddWithWraparound(xreg(instr->Ra()), (rn_s32 * rm_s32));
break;
case SMSUBL_x:
- result = xreg(instr->Ra()) - (rn_s32 * rm_s32);
+ result = base::SubWithWraparound(xreg(instr->Ra()), (rn_s32 * rm_s32));
break;
case UMADDL_x:
- result = xreg(instr->Ra()) + (rn_u32 * rm_u32);
+ result = static_cast<uint64_t>(xreg(instr->Ra())) + (rn_u32 * rm_u32);
break;
case UMSUBL_x:
- result = xreg(instr->Ra()) - (rn_u32 * rm_u32);
+ result = static_cast<uint64_t>(xreg(instr->Ra())) - (rn_u32 * rm_u32);
break;
case SMULH_x:
DCHECK_EQ(instr->Ra(), kZeroRegCode);
@@ -2488,10 +2540,10 @@ void Simulator::BitfieldHelper(Instruction* instr) {
T diff = S - R;
T mask;
if (diff >= 0) {
- mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1
+ mask = diff < reg_size - 1 ? (static_cast<unsignedT>(1) << (diff + 1)) - 1
: static_cast<T>(-1);
} else {
- uint64_t umask = ((1LL << (S + 1)) - 1);
+ uint64_t umask = ((1ULL << (S + 1)) - 1);
umask = (umask >> R) | (umask << (reg_size - R));
mask = static_cast<T>(umask);
diff += reg_size;
@@ -2522,11 +2574,15 @@ void Simulator::BitfieldHelper(Instruction* instr) {
T dst = inzero ? 0 : reg<T>(instr->Rd());
T src = reg<T>(instr->Rn());
// Rotate source bitfield into place.
- T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R));
+ T result = R == 0 ? src
+ : (static_cast<unsignedT>(src) >> R) |
+ (static_cast<unsignedT>(src) << (reg_size - R));
// Determine the sign extension.
- T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1;
- T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
- << (diff + 1);
+ T topbits_preshift = (static_cast<unsignedT>(1) << (reg_size - diff - 1)) - 1;
+ T signbits =
+ diff >= reg_size - 1
+ ? 0
+ : ((extend && ((src >> S) & 1) ? topbits_preshift : 0) << (diff + 1));
// Merge sign extension, dest/zero and bitfield.
result = signbits | (result & mask) | (dst & ~mask);