diff options
Diffstat (limited to 'deps/v8/src/execution/arm64/simulator-arm64.cc')
-rw-r--r-- | deps/v8/src/execution/arm64/simulator-arm64.cc | 130 |
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(®ister_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(®ister_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); |