LibWasm: Remove type information from Value

Gets fib(30) from 380ms to 340ms.
This commit is contained in:
Diego Frias 2024-08-04 08:06:50 -07:00 committed by Ali Mohammad Pur
commit a58704296c
Notes: github-actions[bot] 2024-08-06 23:11:13 +00:00
12 changed files with 349 additions and 287 deletions

View file

@ -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());
}
}
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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 {