// Copyright 2021 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <class Dest, class Source> inline Dest bit_cast(const Source& source) { return mozilla::BitwiseCast<Dest>(source);
}
class Float16 {
public:
Float16() = default;
explicit Float16(float16 value) : bit_pattern_(bit_cast<uint16_t>(value)) { // Check that the provided value is not a NaN to match Float32/64.
MOZ_ASSERT(value == value);
}
static_assert(std::is_trivially_copyable_v<Float16>, "Float16 should be trivially copyable");
// Safety wrapper for a 32-bit floating-point value to make sure we don't lose // the exact bit pattern during deoptimization when passing this value. class Float32 {
public:
Float32() = default;
// This constructor does not guarantee that bit pattern of the input value // is preserved if the input is a NaN. explicit Float32(float value) : bit_pattern_(bit_cast<uint32_t>(value)) { // Check that the provided value is not a NaN, because the bit pattern of a // NaN may be changed by a bit_cast, e.g. for signalling NaNs on // ia32.
MOZ_ASSERT(!std::isnan(value));
}
static_assert(std::is_trivially_copyable_v<Float32>, "Float32 should be trivially copyable");
// Safety wrapper for a 64-bit floating-point value to make sure we don't lose // the exact bit pattern during deoptimization when passing this value. // TODO(ahaas): Unify this class with Double in double.h class Float64 {
public:
Float64() = default;
// This constructor does not guarantee that bit pattern of the input value // is preserved if the input is a NaN. explicit Float64(double value) : bit_pattern_(bit_cast<uint64_t>(value)) { // Check that the provided value is not a NaN, because the bit pattern of a // NaN may be changed by a bit_cast, e.g. for signalling NaNs on // ia32.
MOZ_ASSERT(!std::isnan(value));
}
static_assert(std::is_trivially_copyable_v<Float64>, "Float64 should be trivially copyable");
class Simulator; class Redirection; class CachePage;
// When the SingleStepCallback is called, the simulator is about to execute // sim->get_pc() and the current machine state represents the completed // execution of the previous pc. typedefvoid (*SingleStepCallback)(void* arg, Simulator* sim, void* pc);
// ----------------------------------------------------------------------------- // Utility types and functions for RISCV
using sreg_t = int64_t;
using reg_t = uint64_t;
using freg_t = uint64_t;
using sfreg_t = int64_t;
using FP = mozilla::FloatingPoint<Float>;
static_assert(std::is_same_v<Bits, typename FP::Bits>);
Bits sign; if (n) { // FSGNJN.{S,D}: Result sign bit is the opposite of rs2's sign bit.
sign = ~rs2;
} elseif (x) { // FSGNJX.{S,D}: Result sign bit is the XOR of rs1's and rs2's sign bits.
sign = rs1 ^ rs2;
} else { // FSGNJ.{S,D}: Result sign bit is rs2's sign bit.
sign = rs2;
} return (rs1 & ~FP::kSignBit) | (sign & FP::kSignBit);
}
template <typename Float> inlineFloat fsgnj(Float rs1, Float rs2, bool n, bool x) { if constexpr (std::is_floating_point_v<Float>) {
using Bits = typename mozilla::FloatingPoint<Float>::Bits;
auto rs1_bits = mozilla::BitwiseCast<Bits>(rs1); auto rs2_bits = mozilla::BitwiseCast<Bits>(rs2); auto res_bits = fsgnj_bits<Float>(rs1_bits, rs2_bits, n, x); return mozilla::BitwiseCast<Float>(res_bits);
} else {
using Scalar = decltype(std::declval<Float>().get_scalar());
auto res = fsgnj_bits<Scalar>(rs1.get_bits(), rs2.get_bits(), n, x); returnFloat::FromBits(res);
}
}
} // namespace detail
inlinefloat fsgnj32(float rs1, float rs2, bool n, bool x) { return detail::fsgnj(rs1, rs2, n, x);
}
inline Float32 fsgnj32(Float32 rs1, Float32 rs2, bool n, bool x) { return detail::fsgnj(rs1, rs2, n, x);
}
inlinedouble fsgnj64(double rs1, double rs2, bool n, bool x) { return detail::fsgnj(rs1, rs2, n, x);
}
inline Float64 fsgnj64(Float64 rs1, Float64 rs2, bool n, bool x) { return detail::fsgnj(rs1, rs2, n, x);
}
// Accessors for register state. Reading the pc value adheres to the MIPS // architecture specification and is off by a 8 from the currently executing // instruction. void setRegister(int reg, int64_t value);
int64_t getRegister(int reg) const; // Same for FPURegisters. void setFpuRegister(int fpureg, int64_t value); void setFpuRegisterFloat16(int fpureg, float16 value); void setFpuRegisterFloat(int fpureg, float value); void setFpuRegisterDouble(int fpureg, double value); void setFpuRegisterFloat16(int fpureg, Float16 value); void setFpuRegisterFloat(int fpureg, Float32 value); void setFpuRegisterDouble(int fpureg, Float64 value);
// Returns true if pc register contains one of the 'SpecialValues' defined // below (bad_ra, end_sim_pc). bool has_bad_pc() const;
private: enum SpecialValues { // Known bad pc value to ensure that the simulator does not execute // without being properly setup.
bad_ra = -1, // A pc value used to signal the simulator to stop execution. Generally // the ra is set to this value on transition from native C code to // simulated execution, so that the simulator can "return" to the native // C code.
end_sim_pc = -2, // Unpredictable value.
Unpredictable = 0xbadbeaf
};
bool init();
// Unsupported instructions use Format to print an error and stop execution. void format(const SimInstruction& instr, constchar* format);
// Read and write memory. // RISCV Memory read/write methods template <typename T>
T ReadMem(sreg_t addr, Instruction* instr); template <typename T> void WriteMem(sreg_t addr, T value, Instruction* instr); template <typename T, typename OP>
T amo(sreg_t addr, OP f, Instruction* instr, TraceType t) { auto lhs = ReadMem<T>(addr, instr); // TODO(RISCV): trace memory read for AMO
WriteMem<T>(addr, (T)f(lhs), instr); return lhs;
}
// Handle any wasm faults, returning true if the fault was handled. // This method is rather hot so inline the normal (no-wasm) case. bool MOZ_ALWAYS_INLINE handleWasmSegFault(uint64_t addr, unsigned numBytes) { if (MOZ_LIKELY(!js::wasm::CodeExists)) { returnfalse;
}
uint8_t* newPC; if (!js::wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes,
&newPC)) { returnfalse;
}
// Executes one instruction. void InstructionDecode(const SimInstruction& instr);
// ICache. // static void CheckICache(base::CustomMatcherHashMap* i_cache, // Instruction* instr); // static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t // start, // size_t size); // static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, // void* page); template <typename T, typename Func> inline T CanonicalizeFPUOpFMA(Func fn, T dst, T src1, T src2) {
static_assert(std::is_floating_point<T>::value); auto alu_out = fn(dst, src1, src2); // if any input or result is NaN, the result is quiet_NaN if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
std::isnan(dst)) { // signaling_nan sets kInvalidOperation bit if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(dst)) {
set_fflags(kInvalidOperation);
}
alu_out = std::numeric_limits<T>::quiet_NaN();
} return alu_out;
}
template <typename T, typename Func> inline T CanonicalizeFPUOp3(Func fn) {
static_assert(std::is_floating_point<T>::value);
T src1 = std::is_same<float, T>::value ? frs1() : drs1();
T src2 = std::is_same<float, T>::value ? frs2() : drs2();
T src3 = std::is_same<float, T>::value ? frs3() : drs3(); auto alu_out = fn(src1, src2, src3); // if any input or result is NaN, the result is quiet_NaN if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
std::isnan(src3)) { // signaling_nan sets kInvalidOperation bit if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(src3)) {
set_fflags(kInvalidOperation);
}
alu_out = std::numeric_limits<T>::quiet_NaN();
} return alu_out;
}
template <typename T, typename Func> inline T CanonicalizeFPUOp2(Func fn) {
static_assert(std::is_floating_point<T>::value);
T src1 = std::is_same<float, T>::value ? frs1() : drs1();
T src2 = std::is_same<float, T>::value ? frs2() : drs2(); auto alu_out = fn(src1, src2); // if any input or result is NaN, the result is quiet_NaN if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2)) { // signaling_nan sets kInvalidOperation bit if (isSnan(alu_out) || isSnan(src1) || isSnan(src2)) {
set_fflags(kInvalidOperation);
}
alu_out = std::numeric_limits<T>::quiet_NaN();
} return alu_out;
}
template <typename T, typename Func> inline T CanonicalizeFPUOp1(Func fn) {
static_assert(std::is_floating_point<T>::value);
T src1 = std::is_same<float, T>::value ? frs1() : drs1(); auto alu_out = fn(src1); // if any input or result is NaN, the result is quiet_NaN if (std::isnan(alu_out) || std::isnan(src1)) { // signaling_nan sets kInvalidOperation bit if (isSnan(alu_out) || isSnan(src1)) set_fflags(kInvalidOperation);
alu_out = std::numeric_limits<T>::quiet_NaN();
} return alu_out;
}
// Single-stepping support bool single_stepping_;
SingleStepCallback single_step_callback_; void* single_step_callback_arg_;
// A stop is watched if its code is less than kNumOfWatchedStops. // Only watched stops support enabling/disabling and the counter feature. staticconst uint32_t kNumOfWatchedStops = 256;
// Stop is disabled if bit 31 is set. staticconst uint32_t kStopDisabledBit = 1U << 31;
// A stop is enabled, meaning the simulator will stop when meeting the // instruction, if bit 31 of watchedStops_[code].count is unset. // The value watchedStops_[code].count & ~(1 << 31) indicates how many times // the breakpoint was hit or gone through. struct StopCountAndDesc {
uint32_t count_; char* desc_;
};
StopCountAndDesc watchedStops_[kNumOfWatchedStops];
};
// Process wide simulator state. class SimulatorProcess { friendclass Redirection; friendclass AutoLockSimulatorCache;
// This lock creates a critical section around 'redirection_' and // 'icache_', which are referenced both by the execution engine // and by the off-thread compiler (see Redirection::Get in the cpp file).
Mutex cacheLock_ MOZ_UNANNOTATED;
Redirection* redirection_;
ICacheMap icache_;
public: static ICacheMap& icache() { // Technically we need the lock to access the innards of the // icache, not to take its address, but the latter condition // serves as a useful complement to the former.
singleton_->cacheLock_.assertOwnedByCurrentThread(); return singleton_->icache_;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.