mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:28:10 +00:00
LibWasm: Implement reference instructions (ref.{null,func,is_null})
This commit is contained in:
parent
7fb458b7c9
commit
56bf80251c
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:
|
case Wasm::ValueType::Kind::ExternReference:
|
||||||
arguments.append(Wasm::Value(Wasm::ExternAddress { static_cast<u64>(value) }));
|
arguments.append(Wasm::Value(Wasm::ExternAddress { static_cast<u64>(value) }));
|
||||||
break;
|
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(
|
result.values().first().value().visit(
|
||||||
[&](const auto& value) { return_value = JS::Value(static_cast<double>(value)); },
|
[&](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::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;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,8 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
|
||||||
result.values().first().value().visit(
|
result.values().first().value().visit(
|
||||||
[&](const auto& value) { offset = value; },
|
[&](const auto& value) { offset = value; },
|
||||||
[&](const FunctionAddress&) { instantiation_result = InstantiationError { "Data segment offset returned an address" }; },
|
[&](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())
|
if (instantiation_result.has_value() && instantiation_result->is_error())
|
||||||
return;
|
return;
|
||||||
if (main_module_instance.memories().size() <= data.index.value()) {
|
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)
|
explicit Value(AnyValueType value)
|
||||||
: m_value(move(value))
|
: m_value(move(value))
|
||||||
, m_type(ValueType::I32)
|
, m_type(ValueType::I32)
|
||||||
|
@ -62,6 +66,8 @@ public:
|
||||||
m_type = ValueType { ValueType::FunctionReference };
|
m_type = ValueType { ValueType::FunctionReference };
|
||||||
else if (m_value.has<ExternAddress>())
|
else if (m_value.has<ExternAddress>())
|
||||||
m_type = ValueType { ValueType::ExternReference };
|
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
|
else
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -90,6 +96,14 @@ public:
|
||||||
case ValueType::Kind::F64:
|
case ValueType::Kind::F64:
|
||||||
m_value = bit_cast<double>(raw_value);
|
m_value = bit_cast<double>(raw_value);
|
||||||
break;
|
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:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -139,6 +153,10 @@ public:
|
||||||
[&](const ExternAddress& address) {
|
[&](const ExternAddress& address) {
|
||||||
if constexpr (IsSame<T, ExternAddress>)
|
if constexpr (IsSame<T, ExternAddress>)
|
||||||
result = address;
|
result = address;
|
||||||
|
},
|
||||||
|
[&](const Null& null) {
|
||||||
|
if constexpr (IsSame<T, Null>)
|
||||||
|
result = null;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,8 @@ void Configuration::dump_stack()
|
||||||
v.value().visit([]<typename T>(const T& v) {
|
v.value().visit([]<typename T>(const T& v) {
|
||||||
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
||||||
dbgln(" {}", v);
|
dbgln(" {}", v);
|
||||||
|
else if constexpr (IsSame<Value::Null, T>)
|
||||||
|
dbgln(" *null");
|
||||||
else
|
else
|
||||||
dbgln(" *{}", v.value());
|
dbgln(" *{}", v.value());
|
||||||
});
|
});
|
||||||
|
@ -95,6 +97,8 @@ void Configuration::dump_stack()
|
||||||
local.value().visit([]<typename T>(const T& v) {
|
local.value().visit([]<typename T>(const T& v) {
|
||||||
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
|
||||||
dbgln(" {}", v);
|
dbgln(" {}", v);
|
||||||
|
else if constexpr (IsSame<Value::Null, T>)
|
||||||
|
dbgln(" *null");
|
||||||
else
|
else
|
||||||
dbgln(" *{}", v.value());
|
dbgln(" *{}", v.value());
|
||||||
});
|
});
|
||||||
|
|
|
@ -590,10 +590,29 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi
|
||||||
}
|
}
|
||||||
case Instructions::table_get.value():
|
case Instructions::table_get.value():
|
||||||
case Instructions::table_set.value():
|
case Instructions::table_set.value():
|
||||||
case Instructions::ref_null.value():
|
|
||||||
case Instructions::ref_func.value():
|
|
||||||
case Instructions::ref_is_null.value():
|
|
||||||
goto unimplemented;
|
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():
|
case Instructions::drop.value():
|
||||||
configuration.stack().pop();
|
configuration.stack().pop();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -170,6 +170,8 @@ public:
|
||||||
F64,
|
F64,
|
||||||
FunctionReference,
|
FunctionReference,
|
||||||
ExternReference,
|
ExternReference,
|
||||||
|
NullFunctionReference,
|
||||||
|
NullExternReference,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ValueType(Kind kind)
|
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 is_numeric() const { return !is_reference(); }
|
||||||
auto kind() const { return m_kind; }
|
auto kind() const { return m_kind; }
|
||||||
|
|
||||||
|
@ -198,6 +200,10 @@ public:
|
||||||
return "funcref";
|
return "funcref";
|
||||||
case ExternReference:
|
case ExternReference:
|
||||||
return "externref";
|
return "externref";
|
||||||
|
case NullFunctionReference:
|
||||||
|
return "ref.null externref";
|
||||||
|
case NullExternReference:
|
||||||
|
return "ref.null funcref";
|
||||||
}
|
}
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,10 @@ JS::Value to_js_value(Wasm::Value& wasm_value, JS::GlobalObject& global_object)
|
||||||
case Wasm::ValueType::FunctionReference:
|
case Wasm::ValueType::FunctionReference:
|
||||||
// FIXME: What's the name of a function reference that isn't exported?
|
// 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);
|
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::ExternReference:
|
||||||
|
case Wasm::ValueType::NullExternReference:
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
VERIFY_NOT_REACHED();
|
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::FunctionReference:
|
||||||
case Wasm::ValueType::ExternReference:
|
case Wasm::ValueType::ExternReference:
|
||||||
|
case Wasm::ValueType::NullFunctionReference:
|
||||||
|
case Wasm::ValueType::NullExternReference:
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,9 +202,11 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi
|
||||||
warnln("Returned:");
|
warnln("Returned:");
|
||||||
for (auto& value : result.values()) {
|
for (auto& value : result.values()) {
|
||||||
auto str = value.value().visit(
|
auto str = value.value().visit(
|
||||||
[&](const auto& value) {
|
[&]<typename T>(const T& value) {
|
||||||
if constexpr (requires { value.value(); })
|
if constexpr (requires { value.value(); })
|
||||||
return String::formatted(" -> addr{} ", value.value());
|
return String::formatted(" -> addr{} ", value.value());
|
||||||
|
else if constexpr (IsSame<Wasm::Value::Null, T>)
|
||||||
|
return String::formatted(" ->addr(null)");
|
||||||
else
|
else
|
||||||
return String::formatted(" -> {} ", value);
|
return String::formatted(" -> {} ", value);
|
||||||
});
|
});
|
||||||
|
@ -460,9 +462,11 @@ int main(int argc, char* argv[])
|
||||||
warnln("Returned:");
|
warnln("Returned:");
|
||||||
for (auto& value : result.values()) {
|
for (auto& value : result.values()) {
|
||||||
value.value().visit(
|
value.value().visit(
|
||||||
[&](const auto& value) {
|
[&]<typename T>(const T& value) {
|
||||||
if constexpr (requires { value.value(); })
|
if constexpr (requires { value.value(); })
|
||||||
out(" -> addr{} ", value.value());
|
out(" -> addr{} ", value.value());
|
||||||
|
else if constexpr (IsSame<Wasm::Value::Null, T>)
|
||||||
|
out(" ->addr(null)");
|
||||||
else
|
else
|
||||||
out(" -> {} ", value);
|
out(" -> {} ", value);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue