/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80: */ // 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.
#ifdef JS_SIMULATOR_RISCV64 # include "mozilla/Atomics.h"
# include <vector>
# include "jit/IonTypes.h" # include "jit/riscv64/constant/Constant-riscv64.h" # include "jit/riscv64/constant/util-riscv64.h" # include "jit/riscv64/disasm/Disasm-riscv64.h" # include "js/ProfilingFrameIterator.h" # include "threading/Thread.h" # include "vm/MutexIDs.h" # include "wasm/WasmSignalHandlers.h"
namespace js {
namespace jit {
template <class Dest, class Source> inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source), "bit_cast requires source and destination to be the same size");
static_assert(std::is_trivially_copyable<Dest>::value, "bit_cast requires the destination type to be copyable");
static_assert(std::is_trivially_copyable<Source>::value, "bit_cast requires the source type to be copyable");
Dest dest;
memcpy(&dest, &source, sizeof(dest)); return dest;
}
# define ASSERT_TRIVIALLY_COPYABLE(T) \
static_assert(std::is_trivially_copyable<T>::value, \ #T" should be trivially copyable") # define ASSERT_NOT_TRIVIALLY_COPYABLE(T) \
static_assert(!std::is_trivially_copyable<T>::value, \ #T" should not be trivially copyable")
constexpr uint64_t kHoleNanInt64 =
(static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32; // 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));
}
bool is_nan() const { // Even though {get_scalar()} might flip the quiet NaN bit, it's ok here, // because this does not change the is_nan property. return std::isnan(get_scalar());
}
// Return a pointer to the field storing the bit pattern. Used in code // generation tests to store generated values there directly.
uint32_t* get_bits_address() { return &bit_pattern_; }
// 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));
}
uint64_t get_bits() const { return bit_pattern_; } double get_scalar() const { return bit_cast<double>(bit_pattern_); } bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; } bool is_nan() const { // Even though {get_scalar()} might flip the quiet NaN bit, it's ok here, // because this does not change the is_nan property. return std::isnan(get_scalar());
}
// Return a pointer to the field storing the bit pattern. Used in code // generation tests to store generated values there directly.
uint64_t* get_bits_address() { return &bit_pattern_; }
class Simulator; class Redirection; class CachePage; class AutoLockSimulator;
// 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);
// 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 setFpuRegisterLo(int fpureg, int32_t value); void setFpuRegisterHi(int fpureg, int32_t value); void setFpuRegisterFloat(int fpureg, float value); void setFpuRegisterDouble(int fpureg, double 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(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(Instruction* 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.