mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-03 16:16:43 +00:00
LibWasm: Remove type information from Value
Gets fib(30) from 380ms to 340ms.
This commit is contained in:
parent
a2448308fd
commit
a58704296c
Notes:
github-actions[bot]
2024-08-06 23:11:13 +00:00
Author: https://github.com/dzfrias
Commit: a58704296c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/960
Reviewed-by: https://github.com/alimpfard
12 changed files with 349 additions and 287 deletions
|
@ -55,7 +55,7 @@ Optional<MemoryAddress> Store::allocate(MemoryType const& type)
|
|||
Optional<GlobalAddress> Store::allocate(GlobalType const& type, Value value)
|
||||
{
|
||||
GlobalAddress address { m_globals.size() };
|
||||
m_globals.append(GlobalInstance { move(value), type.is_mutable() });
|
||||
m_globals.append(GlobalInstance { value, type.is_mutable(), type.type() });
|
||||
return address;
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,6 @@ ErrorOr<void, ValidationError> AbstractMachine::validate(Module& module)
|
|||
|
||||
return {};
|
||||
}
|
||||
|
||||
InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<ExternValue> externs)
|
||||
{
|
||||
if (auto result = validate(const_cast<Module&>(module)); result.is_error())
|
||||
|
@ -267,7 +266,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
|
|||
|
||||
for (auto& value : result.values()) {
|
||||
auto reference = value.to<Reference>();
|
||||
references.append(reference.release_value());
|
||||
references.append(reference);
|
||||
}
|
||||
}
|
||||
elements.append(move(references));
|
||||
|
@ -300,8 +299,6 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
|
|||
if (result.is_trap())
|
||||
return InstantiationError { ByteString::formatted("Element section initialisation trapped: {}", result.trap().reason) };
|
||||
auto d = result.values().first().to<i32>();
|
||||
if (!d.has_value())
|
||||
return InstantiationError { "Element section initialisation returned invalid table initial offset" };
|
||||
auto table_instance = m_store.get(main_module_instance.tables()[active_ptr->index.value()]);
|
||||
if (current_index >= main_module_instance.elements().size())
|
||||
return InstantiationError { "Invalid element referenced by active element segment" };
|
||||
|
@ -309,14 +306,14 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
|
|||
return InstantiationError { "Invalid element referenced by active element segment" };
|
||||
|
||||
Checked<size_t> total_size = elem_instance->references().size();
|
||||
total_size.saturating_add(d.value());
|
||||
total_size.saturating_add(d);
|
||||
|
||||
if (total_size.value() > table_instance->elements().size())
|
||||
return InstantiationError { "Table instantiation out of bounds" };
|
||||
|
||||
size_t i = 0;
|
||||
for (auto it = elem_instance->references().begin(); it < elem_instance->references().end(); ++i, ++it)
|
||||
table_instance->elements()[i + d.value()] = *it;
|
||||
table_instance->elements()[i + d] = *it;
|
||||
// Drop element
|
||||
*m_store.get(main_module_instance.elements()[current_index]) = ElementInstance(elem_instance->type(), {});
|
||||
}
|
||||
|
@ -336,10 +333,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
|
|||
auto result = config.execute(interpreter).assert_wasm_result();
|
||||
if (result.is_trap())
|
||||
return InstantiationError { ByteString::formatted("Data section initialisation trapped: {}", result.trap().reason) };
|
||||
size_t offset = TRY(result.values().first().value().visit(
|
||||
[&](auto const& value) { return ErrorOr<size_t, InstantiationError> { value }; },
|
||||
[&](u128 const&) { return ErrorOr<size_t, InstantiationError> { InstantiationError { "Data segment offset returned a vector type"sv } }; },
|
||||
[&](Reference const&) { return ErrorOr<size_t, InstantiationError> { InstantiationError { "Data segment offset returned a reference type"sv } }; }));
|
||||
size_t offset = result.values().first().to<u64>();
|
||||
if (main_module_instance.memories().size() <= data.index.value()) {
|
||||
return InstantiationError {
|
||||
ByteString::formatted("Data segment referenced out-of-bounds memory ({}) of max {} entries",
|
||||
|
@ -570,5 +564,4 @@ void Linker::populate()
|
|||
m_unresolved_imports.set(m_ordered_imports.last());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,45 +75,57 @@ private:
|
|||
class Value {
|
||||
public:
|
||||
Value()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
using AnyValueType = Variant<i32, i64, float, double, u128, Reference>;
|
||||
explicit Value(AnyValueType value)
|
||||
: m_value(move(value))
|
||||
: m_value(u128())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u64)) explicit Value(ValueType type, T raw_value)
|
||||
: m_value(0)
|
||||
requires(sizeof(T) == sizeof(u64)) explicit Value(T raw_value)
|
||||
: m_value(u128(bit_cast<i64>(raw_value), 0))
|
||||
{
|
||||
switch (type.kind()) {
|
||||
case ValueType::Kind::ExternReference:
|
||||
m_value = Reference { Reference::Extern { { bit_cast<u64>(raw_value) } } };
|
||||
break;
|
||||
case ValueType::Kind::FunctionReference:
|
||||
m_value = Reference { Reference::Func { { bit_cast<u64>(raw_value) } } };
|
||||
break;
|
||||
case ValueType::Kind::I32:
|
||||
m_value = static_cast<i32>(bit_cast<i64>(raw_value));
|
||||
break;
|
||||
case ValueType::Kind::I64:
|
||||
m_value = static_cast<i64>(bit_cast<u64>(raw_value));
|
||||
break;
|
||||
case ValueType::Kind::F32:
|
||||
m_value = static_cast<float>(bit_cast<double>(raw_value));
|
||||
break;
|
||||
case ValueType::Kind::F64:
|
||||
m_value = bit_cast<double>(raw_value);
|
||||
break;
|
||||
case ValueType::Kind::V128:
|
||||
m_value = u128(0ull, bit_cast<u64>(raw_value));
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u32)) explicit Value(T raw_value)
|
||||
: m_value(u128(static_cast<i64>(bit_cast<i32>(raw_value)), 0))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u8) && Signed<T>) explicit Value(T raw_value)
|
||||
: m_value(u128(static_cast<i64>(bit_cast<i8>(raw_value)), 0))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u8) && Unsigned<T>) explicit Value(T raw_value)
|
||||
: m_value(u128(static_cast<u64>(bit_cast<u8>(raw_value)), 0))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u16) && Signed<T>) explicit Value(T raw_value)
|
||||
: m_value(u128(static_cast<i64>(bit_cast<i16>(raw_value)), 0))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(sizeof(T) == sizeof(u16) && Unsigned<T>) explicit Value(T raw_value)
|
||||
: m_value(u128(static_cast<u64>(bit_cast<u16>(raw_value)), 0))
|
||||
{
|
||||
}
|
||||
|
||||
explicit Value(Reference ref)
|
||||
{
|
||||
// Reference variant is encoded in the high storage of the u128:
|
||||
// 0: funcref
|
||||
// 1: externref
|
||||
// 2: null funcref
|
||||
// 3: null externref
|
||||
ref.ref().visit(
|
||||
[&](Reference::Func const& func) { m_value = u128(bit_cast<u64>(func.address), 0); },
|
||||
[&](Reference::Extern const& func) { m_value = u128(bit_cast<u64>(func.address), 1); },
|
||||
[&](Reference::Null const& null) { m_value = u128(0, null.type.kind() == ValueType::Kind::FunctionReference ? 2 : 3); });
|
||||
}
|
||||
|
||||
template<SameAs<u128> T>
|
||||
|
@ -128,63 +140,53 @@ public:
|
|||
ALWAYS_INLINE Value& operator=(Value const& value) = default;
|
||||
|
||||
template<typename T>
|
||||
ALWAYS_INLINE Optional<T> to() const
|
||||
ALWAYS_INLINE T to() const
|
||||
{
|
||||
Optional<T> result;
|
||||
m_value.visit(
|
||||
[&](auto value) {
|
||||
if constexpr (IsSame<T, decltype(value)> || (!IsFloatingPoint<T> && IsSame<decltype(value), MakeSigned<T>>)) {
|
||||
result = static_cast<T>(value);
|
||||
} else if constexpr (!IsFloatingPoint<T> && IsConvertible<decltype(value), T>) {
|
||||
// NOTE: No implicit vector <-> scalar conversion.
|
||||
if constexpr (!IsSame<T, u128>) {
|
||||
if (AK::is_within_range<T>(value))
|
||||
result = static_cast<T>(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](u128 value) {
|
||||
if constexpr (IsSame<T, u128>)
|
||||
result = value;
|
||||
},
|
||||
[&](Reference const& value) {
|
||||
if constexpr (IsSame<T, Reference>) {
|
||||
result = value;
|
||||
} else if constexpr (IsSame<T, Reference::Func>) {
|
||||
if (auto ptr = value.ref().template get_pointer<Reference::Func>())
|
||||
result = *ptr;
|
||||
} else if constexpr (IsSame<T, Reference::Extern>) {
|
||||
if (auto ptr = value.ref().template get_pointer<Reference::Extern>())
|
||||
result = *ptr;
|
||||
} else if constexpr (IsSame<T, Reference::Null>) {
|
||||
if (auto ptr = value.ref().template get_pointer<Reference::Null>())
|
||||
result = *ptr;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
if constexpr (IsSame<T, u128>) {
|
||||
return m_value;
|
||||
}
|
||||
if constexpr (IsSame<T, u32>) {
|
||||
u32 low = m_value.low() & 0xFFFFFFFF;
|
||||
return low;
|
||||
}
|
||||
if constexpr (IsSame<T, i32>) {
|
||||
u32 low = m_value.low() & 0xFFFFFFFF;
|
||||
return bit_cast<i32>(low);
|
||||
}
|
||||
if constexpr (IsSame<T, u64>) {
|
||||
return bit_cast<u64>(m_value.low());
|
||||
}
|
||||
if constexpr (IsSame<T, i64>) {
|
||||
return bit_cast<i64>(m_value.low());
|
||||
}
|
||||
if constexpr (IsSame<T, f32>) {
|
||||
u32 low = m_value.low() & 0xFFFFFFFF;
|
||||
return bit_cast<f32>(low);
|
||||
}
|
||||
if constexpr (IsSame<T, f64>) {
|
||||
return bit_cast<f64>(m_value.low());
|
||||
}
|
||||
if constexpr (IsSame<T, Reference>) {
|
||||
switch (m_value.high()) {
|
||||
case 0:
|
||||
return Reference { Reference::Func(bit_cast<FunctionAddress>(m_value.low())) };
|
||||
case 1:
|
||||
return Reference { Reference::Extern(bit_cast<ExternAddress>(m_value.low())) };
|
||||
case 2:
|
||||
return Reference { Reference::Null(ValueType(ValueType::Kind::FunctionReference)) };
|
||||
case 3:
|
||||
return Reference { Reference::Null(ValueType(ValueType::Kind::ExternReference)) };
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ValueType type() const
|
||||
{
|
||||
return ValueType(m_value.visit(
|
||||
[](i32) { return ValueType::Kind::I32; },
|
||||
[](i64) { return ValueType::Kind::I64; },
|
||||
[](float) { return ValueType::Kind::F32; },
|
||||
[](double) { return ValueType::Kind::F64; },
|
||||
[](u128) { return ValueType::Kind::V128; },
|
||||
[&](Reference const& type) {
|
||||
return type.ref().visit(
|
||||
[](Reference::Func const&) { return ValueType::Kind::FunctionReference; },
|
||||
[](Reference::Null const& null_type) {
|
||||
return null_type.type.kind();
|
||||
},
|
||||
[](Reference::Extern const&) { return ValueType::Kind::ExternReference; });
|
||||
}));
|
||||
}
|
||||
auto& value() const { return m_value; }
|
||||
|
||||
private:
|
||||
AnyValueType m_value;
|
||||
u128 m_value;
|
||||
};
|
||||
|
||||
struct Trap {
|
||||
|
@ -481,15 +483,16 @@ private:
|
|||
|
||||
class GlobalInstance {
|
||||
public:
|
||||
explicit GlobalInstance(Value value, bool is_mutable)
|
||||
explicit GlobalInstance(Value value, bool is_mutable, ValueType type)
|
||||
: m_mutable(is_mutable)
|
||||
, m_value(move(value))
|
||||
, m_value(value)
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
auto is_mutable() const { return m_mutable; }
|
||||
auto& value() const { return m_value; }
|
||||
GlobalType type() const { return { m_value.type(), is_mutable() }; }
|
||||
GlobalType type() const { return { m_type, is_mutable() }; }
|
||||
void set_value(Value value)
|
||||
{
|
||||
VERIFY(is_mutable());
|
||||
|
@ -499,6 +502,7 @@ public:
|
|||
private:
|
||||
bool m_mutable { false };
|
||||
Value m_value;
|
||||
ValueType m_type;
|
||||
};
|
||||
|
||||
class DataInstance {
|
||||
|
|
|
@ -75,7 +75,7 @@ void BytecodeInterpreter::load_and_push(Configuration& configuration, Instructio
|
|||
auto& address = configuration.frame().module().memories()[arg.memory_index.value()];
|
||||
auto memory = configuration.store().get(address);
|
||||
auto& entry = configuration.value_stack().last();
|
||||
auto base = *entry.to<i32>();
|
||||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + sizeof(ReadType) > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
|
@ -100,7 +100,7 @@ void BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instru
|
|||
auto& address = configuration.frame().module().memories()[arg.memory_index.value()];
|
||||
auto memory = configuration.store().get(address);
|
||||
auto& entry = configuration.value_stack().last();
|
||||
auto base = *entry.to<i32>();
|
||||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + M * N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
|
@ -127,8 +127,8 @@ void BytecodeInterpreter::load_and_push_lane_n(Configuration& configuration, Ins
|
|||
auto memarg_and_lane = instruction.arguments().get<Instruction::MemoryAndLaneArgument>();
|
||||
auto& address = configuration.frame().module().memories()[memarg_and_lane.memory.memory_index.value()];
|
||||
auto memory = configuration.store().get(address);
|
||||
auto vector = *configuration.value_stack().take_last().to<u128>();
|
||||
auto base = *configuration.value_stack().take_last().to<u32>();
|
||||
auto vector = configuration.value_stack().take_last().to<u128>();
|
||||
auto base = configuration.value_stack().take_last().to<u32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + memarg_and_lane.memory.offset;
|
||||
if (instance_address + N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
|
@ -146,7 +146,7 @@ void BytecodeInterpreter::load_and_push_zero_n(Configuration& configuration, Ins
|
|||
auto memarg_and_lane = instruction.arguments().get<Instruction::MemoryArgument>();
|
||||
auto& address = configuration.frame().module().memories()[memarg_and_lane.memory_index.value()];
|
||||
auto memory = configuration.store().get(address);
|
||||
auto base = *configuration.value_stack().take_last().to<u32>();
|
||||
auto base = configuration.value_stack().take_last().to<u32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + memarg_and_lane.offset;
|
||||
if (instance_address + N / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
|
@ -165,7 +165,7 @@ void BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, In
|
|||
auto& address = configuration.frame().module().memories()[arg.memory_index.value()];
|
||||
auto memory = configuration.store().get(address);
|
||||
auto& entry = configuration.value_stack().last();
|
||||
auto base = *entry.to<i32>();
|
||||
auto base = entry.to<i32>();
|
||||
u64 instance_address = static_cast<u64>(bit_cast<u32>(base)) + arg.offset;
|
||||
if (instance_address + M / 8 > memory->size()) {
|
||||
m_trap = Trap { "Memory access out of bounds" };
|
||||
|
@ -212,7 +212,7 @@ void BytecodeInterpreter::pop_and_push_m_splat(Wasm::Configuration& configuratio
|
|||
using PopT = Conditional<M <= 32, NativeType<32>, NativeType<64>>;
|
||||
using ReadT = NativeType<M>;
|
||||
auto entry = configuration.value_stack().last();
|
||||
auto value = static_cast<ReadT>(*entry.to<PopT>());
|
||||
auto value = static_cast<ReadT>(entry.to<PopT>());
|
||||
dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> splat({})", value, M);
|
||||
set_top_m_splat<M, NativeType>(configuration, value);
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ void BytecodeInterpreter::pop_and_push_m_splat(Wasm::Configuration& configuratio
|
|||
template<typename M, template<typename> typename SetSign, typename VectorType>
|
||||
VectorType BytecodeInterpreter::pop_vector(Configuration& configuration)
|
||||
{
|
||||
return bit_cast<VectorType>(*configuration.value_stack().take_last().to<u128>());
|
||||
return bit_cast<VectorType>(configuration.value_stack().take_last().to<u128>());
|
||||
}
|
||||
|
||||
void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address)
|
||||
|
@ -268,7 +268,7 @@ void BytecodeInterpreter::binary_numeric_operation(Configuration& configuration,
|
|||
auto& lhs_entry = configuration.value_stack().last();
|
||||
auto lhs = lhs_entry.to<PopTypeLHS>();
|
||||
PushType result;
|
||||
auto call_result = Operator { forward<Args>(args)... }(lhs.value(), rhs.value());
|
||||
auto call_result = Operator { forward<Args>(args)... }(lhs, rhs);
|
||||
if constexpr (IsSpecializationOf<decltype(call_result), AK::ErrorOr>) {
|
||||
if (call_result.is_error()) {
|
||||
trap_if_not(false, call_result.error());
|
||||
|
@ -287,7 +287,7 @@ void BytecodeInterpreter::unary_operation(Configuration& configuration, Args&&..
|
|||
{
|
||||
auto& entry = configuration.value_stack().last();
|
||||
auto value = entry.to<PopType>();
|
||||
auto call_result = Operator { forward<Args>(args)... }(*value);
|
||||
auto call_result = Operator { forward<Args>(args)... }(value);
|
||||
PushType result;
|
||||
if constexpr (IsSpecializationOf<decltype(call_result), AK::ErrorOr>) {
|
||||
if (call_result.is_error()) {
|
||||
|
@ -337,19 +337,19 @@ void BytecodeInterpreter::pop_and_store(Configuration& configuration, Instructio
|
|||
{
|
||||
auto& memarg = instruction.arguments().get<Instruction::MemoryArgument>();
|
||||
auto entry = configuration.value_stack().take_last();
|
||||
auto value = ConvertToRaw<StoreT> {}(*entry.to<PopT>());
|
||||
auto value = ConvertToRaw<StoreT> {}(entry.to<PopT>());
|
||||
dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(StoreT));
|
||||
auto base = configuration.value_stack().take_last().to<i32>();
|
||||
store_to_memory(configuration, memarg, { &value, sizeof(StoreT) }, *base);
|
||||
store_to_memory(configuration, memarg, { &value, sizeof(StoreT) }, base);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
void BytecodeInterpreter::pop_and_store_lane_n(Configuration& configuration, Instruction const& instruction)
|
||||
{
|
||||
auto& memarg_and_lane = instruction.arguments().get<Instruction::MemoryAndLaneArgument>();
|
||||
auto vector = *configuration.value_stack().take_last().to<u128>();
|
||||
auto vector = configuration.value_stack().take_last().to<u128>();
|
||||
auto src = bit_cast<u8*>(&vector) + memarg_and_lane.lane * N / 8;
|
||||
auto base = *configuration.value_stack().take_last().to<u32>();
|
||||
auto base = configuration.value_stack().take_last().to<u32>();
|
||||
store_to_memory(configuration, memarg_and_lane.memory, { src, N / 8 }, base);
|
||||
}
|
||||
|
||||
|
@ -422,16 +422,16 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
return;
|
||||
}
|
||||
case Instructions::i32_const.value():
|
||||
configuration.value_stack().append(Value(ValueType { ValueType::I32 }, static_cast<i64>(instruction.arguments().get<i32>())));
|
||||
configuration.value_stack().append(Value(instruction.arguments().get<i32>()));
|
||||
return;
|
||||
case Instructions::i64_const.value():
|
||||
configuration.value_stack().append(Value(ValueType { ValueType::I64 }, instruction.arguments().get<i64>()));
|
||||
configuration.value_stack().append(Value(instruction.arguments().get<i64>()));
|
||||
return;
|
||||
case Instructions::f32_const.value():
|
||||
configuration.value_stack().append(Value(Value::AnyValueType(instruction.arguments().get<float>())));
|
||||
configuration.value_stack().append(Value(instruction.arguments().get<float>()));
|
||||
return;
|
||||
case Instructions::f64_const.value():
|
||||
configuration.value_stack().append(Value(Value::AnyValueType(instruction.arguments().get<double>())));
|
||||
configuration.value_stack().append(Value(instruction.arguments().get<double>()));
|
||||
return;
|
||||
case Instructions::block.value(): {
|
||||
size_t arity = 0;
|
||||
|
@ -513,13 +513,13 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
return branch_to_label(configuration, instruction.arguments().get<LabelIndex>());
|
||||
case Instructions::br_if.value(): {
|
||||
auto cond = configuration.value_stack().take_last().to<i32>();
|
||||
if (*cond == 0)
|
||||
if (cond == 0)
|
||||
return;
|
||||
return branch_to_label(configuration, instruction.arguments().get<LabelIndex>());
|
||||
}
|
||||
case Instructions::br_table.value(): {
|
||||
auto& arguments = instruction.arguments().get<Instruction::TableBranchArgs>();
|
||||
auto i = *configuration.value_stack().take_last().to<u32>();
|
||||
auto i = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
if (i >= arguments.labels.size()) {
|
||||
return branch_to_label(configuration, arguments.default_);
|
||||
|
@ -538,12 +538,12 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto table_address = configuration.frame().module().tables()[args.table.value()];
|
||||
auto table_instance = configuration.store().get(table_address);
|
||||
auto index = configuration.value_stack().take_last().to<i32>();
|
||||
TRAP_IF_NOT(index.value() >= 0);
|
||||
TRAP_IF_NOT(static_cast<size_t>(index.value()) < table_instance->elements().size());
|
||||
auto element = table_instance->elements()[index.value()];
|
||||
TRAP_IF_NOT(index >= 0);
|
||||
TRAP_IF_NOT(static_cast<size_t>(index) < table_instance->elements().size());
|
||||
auto element = table_instance->elements()[index];
|
||||
TRAP_IF_NOT(element.ref().has<Reference::Func>());
|
||||
auto address = element.ref().get<Reference::Func>().address;
|
||||
dbgln_if(WASM_TRACE_DEBUG, "call_indirect({} -> {})", index.value(), address.value());
|
||||
dbgln_if(WASM_TRACE_DEBUG, "call_indirect({} -> {})", index, address.value());
|
||||
call_address(configuration, address);
|
||||
return;
|
||||
}
|
||||
|
@ -636,8 +636,8 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
i32 old_pages = instance->size() / Constants::page_size;
|
||||
auto& entry = configuration.value_stack().last();
|
||||
auto new_pages = entry.to<i32>();
|
||||
dbgln_if(WASM_TRACE_DEBUG, "memory.grow({}), previously {} pages...", *new_pages, old_pages);
|
||||
if (instance->grow(new_pages.value() * Constants::page_size))
|
||||
dbgln_if(WASM_TRACE_DEBUG, "memory.grow({}), previously {} pages...", new_pages, old_pages);
|
||||
if (instance->grow(new_pages * Constants::page_size))
|
||||
entry = Value((i32)old_pages);
|
||||
else
|
||||
entry = Value((i32)-1);
|
||||
|
@ -648,9 +648,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto& args = instruction.arguments().get<Instruction::MemoryIndexArgument>();
|
||||
auto address = configuration.frame().module().memories()[args.memory_index.value()];
|
||||
auto instance = configuration.store().get(address);
|
||||
auto count = configuration.value_stack().take_last().to<u32>().value();
|
||||
u8 value = static_cast<u8>(configuration.value_stack().take_last().to<u32>().value());
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>().value();
|
||||
auto count = configuration.value_stack().take_last().to<u32>();
|
||||
u8 value = static_cast<u8>(configuration.value_stack().take_last().to<u32>());
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
TRAP_IF_NOT(static_cast<size_t>(destination_offset + count) <= instance->data().size());
|
||||
|
||||
|
@ -670,9 +670,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto source_instance = configuration.store().get(source_address);
|
||||
auto destination_instance = configuration.store().get(destination_address);
|
||||
|
||||
auto count = configuration.value_stack().take_last().to<i32>().value();
|
||||
auto source_offset = configuration.value_stack().take_last().to<i32>().value();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<i32>().value();
|
||||
auto count = configuration.value_stack().take_last().to<i32>();
|
||||
auto source_offset = configuration.value_stack().take_last().to<i32>();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<i32>();
|
||||
|
||||
Checked<size_t> source_position = source_offset;
|
||||
source_position.saturating_add(count);
|
||||
|
@ -706,9 +706,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto& data = *configuration.store().get(data_address);
|
||||
auto memory_address = configuration.frame().module().memories()[args.memory_index.value()];
|
||||
auto memory = configuration.store().get(memory_address);
|
||||
auto count = *configuration.value_stack().take_last().to<u32>();
|
||||
auto source_offset = *configuration.value_stack().take_last().to<u32>();
|
||||
auto destination_offset = *configuration.value_stack().take_last().to<u32>();
|
||||
auto count = configuration.value_stack().take_last().to<u32>();
|
||||
auto source_offset = configuration.value_stack().take_last().to<u32>();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
Checked<size_t> source_position = source_offset;
|
||||
source_position.saturating_add(count);
|
||||
|
@ -747,9 +747,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto table = configuration.store().get(table_address);
|
||||
auto element_address = configuration.frame().module().elements()[args.element_index.value()];
|
||||
auto element = configuration.store().get(element_address);
|
||||
auto count = *configuration.value_stack().take_last().to<u32>();
|
||||
auto source_offset = *configuration.value_stack().take_last().to<u32>();
|
||||
auto destination_offset = *configuration.value_stack().take_last().to<u32>();
|
||||
auto count = configuration.value_stack().take_last().to<u32>();
|
||||
auto source_offset = configuration.value_stack().take_last().to<u32>();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
Checked<u32> checked_source_offset = source_offset;
|
||||
Checked<u32> checked_destination_offset = destination_offset;
|
||||
|
@ -769,9 +769,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto source_instance = configuration.store().get(source_address);
|
||||
auto destination_instance = configuration.store().get(destination_address);
|
||||
|
||||
auto count = configuration.value_stack().take_last().to<u32>().value();
|
||||
auto source_offset = configuration.value_stack().take_last().to<u32>().value();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>().value();
|
||||
auto count = configuration.value_stack().take_last().to<u32>();
|
||||
auto source_offset = configuration.value_stack().take_last().to<u32>();
|
||||
auto destination_offset = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
Checked<size_t> source_position = source_offset;
|
||||
source_position.saturating_add(count);
|
||||
|
@ -801,9 +801,9 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto table_index = instruction.arguments().get<TableIndex>();
|
||||
auto address = configuration.frame().module().tables()[table_index.value()];
|
||||
auto table = configuration.store().get(address);
|
||||
auto count = *configuration.value_stack().take_last().to<u32>();
|
||||
auto value = *configuration.value_stack().take_last().to<Reference>();
|
||||
auto start = *configuration.value_stack().take_last().to<u32>();
|
||||
auto count = configuration.value_stack().take_last().to<u32>();
|
||||
auto value = configuration.value_stack().take_last().to<Reference>();
|
||||
auto start = configuration.value_stack().take_last().to<u32>();
|
||||
|
||||
Checked<u32> checked_offset = start;
|
||||
checked_offset += count;
|
||||
|
@ -814,8 +814,8 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
return;
|
||||
}
|
||||
case Instructions::table_set.value(): {
|
||||
auto ref = *configuration.value_stack().take_last().to<Reference>();
|
||||
auto index = (size_t)(*configuration.value_stack().take_last().to<i32>());
|
||||
auto ref = configuration.value_stack().take_last().to<Reference>();
|
||||
auto index = (size_t)(configuration.value_stack().take_last().to<i32>());
|
||||
auto table_index = instruction.arguments().get<TableIndex>();
|
||||
auto address = configuration.frame().module().tables()[table_index.value()];
|
||||
auto table = configuration.store().get(address);
|
||||
|
@ -824,7 +824,7 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
return;
|
||||
}
|
||||
case Instructions::table_get.value(): {
|
||||
auto index = (size_t)(*configuration.value_stack().take_last().to<i32>());
|
||||
auto index = (size_t)(configuration.value_stack().take_last().to<i32>());
|
||||
auto table_index = instruction.arguments().get<TableIndex>();
|
||||
auto address = configuration.frame().module().tables()[table_index.value()];
|
||||
auto table = configuration.store().get(address);
|
||||
|
@ -834,8 +834,8 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
return;
|
||||
}
|
||||
case Instructions::table_grow.value(): {
|
||||
auto size = *configuration.value_stack().take_last().to<u32>();
|
||||
auto fill_value = *configuration.value_stack().take_last().to<Reference>();
|
||||
auto size = configuration.value_stack().take_last().to<u32>();
|
||||
auto fill_value = configuration.value_stack().take_last().to<Reference>();
|
||||
auto table_index = instruction.arguments().get<TableIndex>();
|
||||
auto address = configuration.frame().module().tables()[table_index.value()];
|
||||
auto table = configuration.store().get(address);
|
||||
|
@ -864,12 +864,12 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
auto index = instruction.arguments().get<FunctionIndex>().value();
|
||||
auto& functions = configuration.frame().module().functions();
|
||||
auto address = functions[index];
|
||||
configuration.value_stack().append(Value(ValueType(ValueType::FunctionReference), address.value()));
|
||||
configuration.value_stack().append(Value(address.value()));
|
||||
return;
|
||||
}
|
||||
case Instructions::ref_is_null.value(): {
|
||||
auto ref = configuration.value_stack().take_last().to<Reference::Null>();
|
||||
configuration.value_stack().append(Value(static_cast<i32>(ref.has_value() ? 1 : 0)));
|
||||
auto ref = configuration.value_stack().take_last().to<Reference>();
|
||||
configuration.value_stack().append(Value(static_cast<i32>(ref.ref().has<Reference::Null>() ? 1 : 0)));
|
||||
return;
|
||||
}
|
||||
case Instructions::drop.value():
|
||||
|
@ -879,10 +879,10 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
case Instructions::select_typed.value(): {
|
||||
// Note: The type seems to only be used for validation.
|
||||
auto value = configuration.value_stack().take_last().to<i32>();
|
||||
dbgln_if(WASM_TRACE_DEBUG, "select({})", value.value());
|
||||
dbgln_if(WASM_TRACE_DEBUG, "select({})", value);
|
||||
auto rhs = configuration.value_stack().take_last();
|
||||
auto& lhs = configuration.value_stack().last();
|
||||
lhs = value.value() != 0 ? lhs : rhs;
|
||||
lhs = value != 0 ? lhs : rhs;
|
||||
return;
|
||||
}
|
||||
case Instructions::i32_eqz.value():
|
||||
|
@ -1579,15 +1579,15 @@ ALWAYS_INLINE void BytecodeInterpreter::interpret_instruction(Configuration& con
|
|||
case Instructions::v128_andnot.value():
|
||||
return binary_numeric_operation<u128, u128, Operators::BitAndNot>(configuration);
|
||||
case Instructions::v128_bitselect.value(): {
|
||||
auto mask = *configuration.value_stack().take_last().to<u128>();
|
||||
auto false_vector = *configuration.value_stack().take_last().to<u128>();
|
||||
auto true_vector = *configuration.value_stack().take_last().to<u128>();
|
||||
auto mask = configuration.value_stack().take_last().to<u128>();
|
||||
auto false_vector = configuration.value_stack().take_last().to<u128>();
|
||||
auto true_vector = configuration.value_stack().take_last().to<u128>();
|
||||
u128 result = (true_vector & mask) | (false_vector & ~mask);
|
||||
configuration.value_stack().append(Value(result));
|
||||
return;
|
||||
}
|
||||
case Instructions::v128_any_true.value(): {
|
||||
auto vector = *configuration.value_stack().take_last().to<u128>();
|
||||
auto vector = configuration.value_stack().take_last().to<u128>();
|
||||
configuration.value_stack().append(Value(static_cast<i32>(vector != 0)));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Ve
|
|||
locals.ensure_capacity(locals.size() + wasm_function->code().func().locals().size());
|
||||
for (auto& local : wasm_function->code().func().locals()) {
|
||||
for (size_t i = 0; i < local.n(); ++i)
|
||||
locals.empend(local.type(), 0ull);
|
||||
locals.append(Value());
|
||||
}
|
||||
|
||||
set_frame(Frame {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue