mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:32:45 +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
	
	 Ali Mohammad Pur
						Ali Mohammad Pur