mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
LibWasm: Implement reference instructions (ref.{null,func,is_null})
This commit is contained in:
parent
7fb458b7c9
commit
56bf80251c
Notes:
sideshowbarker
2024-07-18 17:01:23 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/56bf80251c1 Pull-request: https://github.com/SerenityOS/serenity/pull/7670
8 changed files with 73 additions and 9 deletions
|
@ -190,6 +190,12 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
|
|||
case Wasm::ValueType::Kind::ExternReference:
|
||||
arguments.append(Wasm::Value(Wasm::ExternAddress { static_cast<u64>(value) }));
|
||||
break;
|
||||
case Wasm::ValueType::Kind::NullFunctionReference:
|
||||
arguments.append(Wasm::Value(Wasm::Value::Null { Wasm::ValueType(Wasm::ValueType::Kind::FunctionReference) }));
|
||||
break;
|
||||
case Wasm::ValueType::Kind::NullExternReference:
|
||||
arguments.append(Wasm::Value(Wasm::Value::Null { Wasm::ValueType(Wasm::ValueType::Kind::ExternReference) }));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,6 +212,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
|
|||
result.values().first().value().visit(
|
||||
[&](const auto& value) { return_value = JS::Value(static_cast<double>(value)); },
|
||||
[&](const Wasm::FunctionAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); },
|
||||
[&](const Wasm::ExternAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); });
|
||||
[&](const Wasm::ExternAddress& index) { return_value = JS::Value(static_cast<double>(index.value())); },
|
||||
[&](const Wasm::Value::Null&) { return_value = JS::js_null(); });
|
||||
return return_value;
|
||||
}
|
||||
|
|
|
@ -152,7 +152,8 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
|
|||
result.values().first().value().visit(
|
||||
[&](const auto& value) { offset = value; },
|
||||
[&](const FunctionAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; },
|
||||
[&](const ExternAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; });
|
||||
[&](const ExternAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; },
|
||||
[&](const Value::Null&) { instantiation_result = InstantiationError { "Data segment offset returned a null reference" }; });
|
||||
if (instantiation_result.has_value() && instantiation_result->is_error())
|
||||
return;
|
||||
if (main_module_instance.memories().size() <= data.index.value()) {
|
||||
|
|
|
@ -45,7 +45,11 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
using AnyValueType = Variant<i32, i64, float, double, FunctionAddress, ExternAddress>;
|
||||
struct Null {
|
||||
ValueType type;
|
||||
};
|
||||
|
||||
using AnyValueType = Variant<i32, i64, float, double, FunctionAddress, ExternAddress, Null>;
|
||||
explicit Value(AnyValueType value)
|
||||
: m_value(move(value))
|
||||
, m_type(ValueType::I32)
|
||||
|
@ -62,6 +66,8 @@ public:
|
|||
m_type = ValueType { ValueType::FunctionReference };
|
||||
else if (m_value.has<ExternAddress>())
|
||||
m_type = ValueType { ValueType::ExternReference };
|
||||
else if (m_value.has<Null>())
|
||||
m_type = ValueType { m_value.get<Null>().type.kind() == ValueType::ExternReference ? ValueType::NullExternReference : ValueType::NullFunctionReference };
|
||||
else
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -90,6 +96,14 @@ public:
|
|||
case ValueType::Kind::F64:
|
||||
m_value = bit_cast<double>(raw_value);
|
||||
break;
|
||||
case ValueType::Kind::NullFunctionReference:
|
||||
VERIFY(raw_value == 0);
|
||||
m_value = Null { ValueType(ValueType::Kind::FunctionReference) };
|
||||
break;
|
||||
case ValueType::Kind::NullExternReference:
|
||||
VERIFY(raw_value == 0);
|
||||
m_value = Null { ValueType(ValueType::Kind::ExternReference) };
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -139,6 +153,10 @@ public:
|
|||
[&](const ExternAddress& address) {
|
||||
if constexpr (IsSame<T, ExternAddress>)
|
||||
result = address;
|
||||
},
|
||||
[&](const Null& null) {
|
||||
if constexpr (IsSame<T, Null>)
|
||||
result = null;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ void Configuration::dump_stack()
|
|||
v.value().visit([]<typename T>(const T& v) {
|
||||
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
||||
dbgln(" {}", v);
|
||||
else if constexpr (IsSame<Value::Null, T>)
|
||||
dbgln(" *null");
|
||||
else
|
||||
dbgln(" *{}", v.value());
|
||||
});
|
||||
|
@ -95,6 +97,8 @@ void Configuration::dump_stack()
|
|||
local.value().visit([]<typename T>(const T& v) {
|
||||
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
||||
dbgln(" {}", v);
|
||||
else if constexpr (IsSame<Value::Null, T>)
|
||||
dbgln(" *null");
|
||||
else
|
||||
dbgln(" *{}", v.value());
|
||||
});
|
||||
|
|
|
@ -590,10 +590,29 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi
|
|||
}
|
||||
case Instructions::table_get.value():
|
||||
case Instructions::table_set.value():
|
||||
case Instructions::ref_null.value():
|
||||
case Instructions::ref_func.value():
|
||||
case Instructions::ref_is_null.value():
|
||||
goto unimplemented;
|
||||
case Instructions::ref_null.value(): {
|
||||
auto type = instruction.arguments().get<ValueType>();
|
||||
TRAP_IF_NOT(type.is_reference());
|
||||
configuration.stack().push(Value(Value::Null { type }));
|
||||
return;
|
||||
};
|
||||
case Instructions::ref_func.value(): {
|
||||
auto index = instruction.arguments().get<FunctionIndex>().value();
|
||||
auto& functions = configuration.frame().module().functions();
|
||||
TRAP_IF_NOT(functions.size() > index);
|
||||
auto address = functions[index];
|
||||
configuration.stack().push(Value(ValueType(ValueType::FunctionReference), address.value()));
|
||||
return;
|
||||
}
|
||||
case Instructions::ref_is_null.value(): {
|
||||
auto top = configuration.stack().peek().get_pointer<Value>();
|
||||
TRAP_IF_NOT(top);
|
||||
TRAP_IF_NOT(top->type().is_reference());
|
||||
auto is_null = top->to<Value::Null>().has_value();
|
||||
configuration.stack().peek() = Value(ValueType(ValueType::I32), static_cast<u64>(is_null ? 1 : 0));
|
||||
return;
|
||||
}
|
||||
case Instructions::drop.value():
|
||||
configuration.stack().pop();
|
||||
return;
|
||||
|
|
|
@ -170,6 +170,8 @@ public:
|
|||
F64,
|
||||
FunctionReference,
|
||||
ExternReference,
|
||||
NullFunctionReference,
|
||||
NullExternReference,
|
||||
};
|
||||
|
||||
explicit ValueType(Kind kind)
|
||||
|
@ -177,7 +179,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference; }
|
||||
auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == NullExternReference || m_kind == NullFunctionReference; }
|
||||
auto is_numeric() const { return !is_reference(); }
|
||||
auto kind() const { return m_kind; }
|
||||
|
||||
|
@ -198,6 +200,10 @@ public:
|
|||
return "funcref";
|
||||
case ExternReference:
|
||||
return "externref";
|
||||
case NullFunctionReference:
|
||||
return "ref.null externref";
|
||||
case NullExternReference:
|
||||
return "ref.null funcref";
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -262,7 +262,10 @@ JS::Value to_js_value(Wasm::Value& wasm_value, JS::GlobalObject& global_object)
|
|||
case Wasm::ValueType::FunctionReference:
|
||||
// FIXME: What's the name of a function reference that isn't exported?
|
||||
return create_native_function(wasm_value.to<Wasm::FunctionAddress>().value(), "FIXME_IHaveNoIdeaWhatThisShouldBeCalled", global_object);
|
||||
case Wasm::ValueType::NullFunctionReference:
|
||||
return JS::js_null();
|
||||
case Wasm::ValueType::ExternReference:
|
||||
case Wasm::ValueType::NullExternReference:
|
||||
TODO();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -304,6 +307,8 @@ Optional<Wasm::Value> to_webassembly_value(JS::Value value, const Wasm::ValueTyp
|
|||
}
|
||||
case Wasm::ValueType::FunctionReference:
|
||||
case Wasm::ValueType::ExternReference:
|
||||
case Wasm::ValueType::NullFunctionReference:
|
||||
case Wasm::ValueType::NullExternReference:
|
||||
TODO();
|
||||
}
|
||||
|
||||
|
|
|
@ -202,9 +202,11 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi
|
|||
warnln("Returned:");
|
||||
for (auto& value : result.values()) {
|
||||
auto str = value.value().visit(
|
||||
[&](const auto& value) {
|
||||
[&]<typename T>(const T& value) {
|
||||
if constexpr (requires { value.value(); })
|
||||
return String::formatted(" -> addr{} ", value.value());
|
||||
else if constexpr (IsSame<Wasm::Value::Null, T>)
|
||||
return String::formatted(" ->addr(null)");
|
||||
else
|
||||
return String::formatted(" -> {} ", value);
|
||||
});
|
||||
|
@ -460,9 +462,11 @@ int main(int argc, char* argv[])
|
|||
warnln("Returned:");
|
||||
for (auto& value : result.values()) {
|
||||
value.value().visit(
|
||||
[&](const auto& value) {
|
||||
[&]<typename T>(const T& value) {
|
||||
if constexpr (requires { value.value(); })
|
||||
out(" -> addr{} ", value.value());
|
||||
else if constexpr (IsSame<Wasm::Value::Null, T>)
|
||||
out(" ->addr(null)");
|
||||
else
|
||||
out(" -> {} ", value);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue