Serenity Operating System
at master 642 lines 20 kB view raw
1/* 2 * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Function.h> 10#include <AK/HashMap.h> 11#include <AK/HashTable.h> 12#include <AK/OwnPtr.h> 13#include <AK/Result.h> 14#include <LibWasm/Types.h> 15 16// NOTE: Special case for Wasm::Result. 17#include <LibJS/Runtime/Completion.h> 18 19namespace Wasm { 20 21class Configuration; 22struct Interpreter; 23 24struct InstantiationError { 25 DeprecatedString error { "Unknown error" }; 26}; 27struct LinkError { 28 enum OtherErrors { 29 InvalidImportedModule, 30 }; 31 Vector<DeprecatedString> missing_imports; 32 Vector<OtherErrors> other_errors; 33}; 34 35AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, FunctionAddress, Arithmetic, Comparison, Increment); 36AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, ExternAddress, Arithmetic, Comparison, Increment); 37AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, TableAddress, Arithmetic, Comparison, Increment); 38AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, GlobalAddress, Arithmetic, Comparison, Increment); 39AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, ElementAddress, Arithmetic, Comparison, Increment); 40AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, DataAddress, Arithmetic, Comparison, Increment); 41AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, MemoryAddress, Arithmetic, Comparison, Increment); 42 43// FIXME: These should probably be made generic/virtual if/when we decide to do something more 44// fancy than just a dumb interpreter. 45class Reference { 46public: 47 struct Null { 48 ValueType type; 49 }; 50 struct Func { 51 FunctionAddress address; 52 }; 53 struct Extern { 54 ExternAddress address; 55 }; 56 57 using RefType = Variant<Null, Func, Extern>; 58 explicit Reference(RefType ref) 59 : m_ref(move(ref)) 60 { 61 } 62 63 auto& ref() const { return m_ref; } 64 65private: 66 RefType m_ref; 67}; 68 69class Value { 70public: 71 Value() 72 : m_value(0) 73 { 74 } 75 76 using AnyValueType = Variant<i32, i64, float, double, Reference>; 77 explicit Value(AnyValueType value) 78 : m_value(move(value)) 79 { 80 } 81 82 template<typename T> 83 requires(sizeof(T) == sizeof(u64)) explicit Value(ValueType type, T raw_value) 84 : m_value(0) 85 { 86 switch (type.kind()) { 87 case ValueType::Kind::ExternReference: 88 m_value = Reference { Reference::Extern { { bit_cast<u64>(raw_value) } } }; 89 break; 90 case ValueType::Kind::FunctionReference: 91 m_value = Reference { Reference::Func { { bit_cast<u64>(raw_value) } } }; 92 break; 93 case ValueType::Kind::I32: 94 m_value = static_cast<i32>(bit_cast<i64>(raw_value)); 95 break; 96 case ValueType::Kind::I64: 97 m_value = static_cast<i64>(bit_cast<u64>(raw_value)); 98 break; 99 case ValueType::Kind::F32: 100 m_value = static_cast<float>(bit_cast<double>(raw_value)); 101 break; 102 case ValueType::Kind::F64: 103 m_value = bit_cast<double>(raw_value); 104 break; 105 case ValueType::Kind::NullFunctionReference: 106 VERIFY(raw_value == 0); 107 m_value = Reference { Reference::Null { ValueType(ValueType::Kind::FunctionReference) } }; 108 break; 109 case ValueType::Kind::NullExternReference: 110 VERIFY(raw_value == 0); 111 m_value = Reference { Reference::Null { ValueType(ValueType::Kind::ExternReference) } }; 112 break; 113 default: 114 VERIFY_NOT_REACHED(); 115 } 116 } 117 118 ALWAYS_INLINE Value(Value const& value) = default; 119 ALWAYS_INLINE Value(Value&& value) = default; 120 ALWAYS_INLINE Value& operator=(Value&& value) = default; 121 ALWAYS_INLINE Value& operator=(Value const& value) = default; 122 123 template<typename T> 124 ALWAYS_INLINE Optional<T> to() 125 { 126 Optional<T> result; 127 m_value.visit( 128 [&](auto value) { 129 if constexpr (IsSame<T, decltype(value)>) 130 result = value; 131 else if constexpr (!IsFloatingPoint<T> && IsSame<decltype(value), MakeSigned<T>>) 132 result = value; 133 }, 134 [&](Reference const& value) { 135 if constexpr (IsSame<T, Reference>) { 136 result = value; 137 } else if constexpr (IsSame<T, Reference::Func>) { 138 if (auto ptr = value.ref().template get_pointer<Reference::Func>()) 139 result = *ptr; 140 } else if constexpr (IsSame<T, Reference::Extern>) { 141 if (auto ptr = value.ref().template get_pointer<Reference::Extern>()) 142 result = *ptr; 143 } else if constexpr (IsSame<T, Reference::Null>) { 144 if (auto ptr = value.ref().template get_pointer<Reference::Null>()) 145 result = *ptr; 146 } 147 }); 148 return result; 149 } 150 151 ValueType type() const 152 { 153 return ValueType(m_value.visit( 154 [](i32) { return ValueType::Kind::I32; }, 155 [](i64) { return ValueType::Kind::I64; }, 156 [](float) { return ValueType::Kind::F32; }, 157 [](double) { return ValueType::Kind::F64; }, 158 [&](Reference const& type) { 159 return type.ref().visit( 160 [](Reference::Func const&) { return ValueType::Kind::FunctionReference; }, 161 [](Reference::Null const& null_type) { 162 return null_type.type.kind() == ValueType::ExternReference ? ValueType::Kind::NullExternReference : ValueType::Kind::NullFunctionReference; 163 }, 164 [](Reference::Extern const&) { return ValueType::Kind::ExternReference; }); 165 })); 166 } 167 auto& value() const { return m_value; } 168 169private: 170 AnyValueType m_value; 171}; 172 173struct Trap { 174 DeprecatedString reason; 175}; 176 177// A variant of Result that does not include external reasons for error (JS::Completion, for now). 178class PureResult { 179public: 180 explicit PureResult(Vector<Value> values) 181 : m_result(move(values)) 182 { 183 } 184 185 PureResult(Trap trap) 186 : m_result(move(trap)) 187 { 188 } 189 190 auto is_trap() const { return m_result.has<Trap>(); } 191 auto& values() const { return m_result.get<Vector<Value>>(); } 192 auto& values() { return m_result.get<Vector<Value>>(); } 193 auto& trap() const { return m_result.get<Trap>(); } 194 auto& trap() { return m_result.get<Trap>(); } 195 196private: 197 friend class Result; 198 explicit PureResult(Variant<Vector<Value>, Trap>&& result) 199 : m_result(move(result)) 200 { 201 } 202 203 Variant<Vector<Value>, Trap> m_result; 204}; 205 206class Result { 207public: 208 explicit Result(Vector<Value> values) 209 : m_result(move(values)) 210 { 211 } 212 213 Result(Trap trap) 214 : m_result(move(trap)) 215 { 216 } 217 218 Result(JS::Completion completion) 219 : m_result(move(completion)) 220 { 221 VERIFY(m_result.get<JS::Completion>().is_abrupt()); 222 } 223 224 Result(PureResult&& result) 225 : m_result(result.m_result.downcast<decltype(m_result)>()) 226 { 227 } 228 229 auto is_trap() const { return m_result.has<Trap>(); } 230 auto is_completion() const { return m_result.has<JS::Completion>(); } 231 auto& values() const { return m_result.get<Vector<Value>>(); } 232 auto& values() { return m_result.get<Vector<Value>>(); } 233 auto& trap() const { return m_result.get<Trap>(); } 234 auto& trap() { return m_result.get<Trap>(); } 235 auto& completion() { return m_result.get<JS::Completion>(); } 236 auto& completion() const { return m_result.get<JS::Completion>(); } 237 238 PureResult assert_wasm_result() && 239 { 240 VERIFY(!is_completion()); 241 return PureResult(move(m_result).downcast<Vector<Value>, Trap>()); 242 } 243 244private: 245 Variant<Vector<Value>, Trap, JS::Completion> m_result; 246}; 247 248using ExternValue = Variant<FunctionAddress, TableAddress, MemoryAddress, GlobalAddress>; 249 250class ExportInstance { 251public: 252 explicit ExportInstance(DeprecatedString name, ExternValue value) 253 : m_name(move(name)) 254 , m_value(move(value)) 255 { 256 } 257 258 auto& name() const { return m_name; } 259 auto& value() const { return m_value; } 260 261private: 262 DeprecatedString m_name; 263 ExternValue m_value; 264}; 265 266class ModuleInstance { 267public: 268 explicit ModuleInstance( 269 Vector<FunctionType> types, Vector<FunctionAddress> function_addresses, Vector<TableAddress> table_addresses, 270 Vector<MemoryAddress> memory_addresses, Vector<GlobalAddress> global_addresses, Vector<DataAddress> data_addresses, 271 Vector<ExportInstance> exports) 272 : m_types(move(types)) 273 , m_functions(move(function_addresses)) 274 , m_tables(move(table_addresses)) 275 , m_memories(move(memory_addresses)) 276 , m_globals(move(global_addresses)) 277 , m_datas(move(data_addresses)) 278 , m_exports(move(exports)) 279 { 280 } 281 282 ModuleInstance() = default; 283 284 auto& types() const { return m_types; } 285 auto& functions() const { return m_functions; } 286 auto& tables() const { return m_tables; } 287 auto& memories() const { return m_memories; } 288 auto& globals() const { return m_globals; } 289 auto& elements() const { return m_elements; } 290 auto& datas() const { return m_datas; } 291 auto& exports() const { return m_exports; } 292 293 auto& types() { return m_types; } 294 auto& functions() { return m_functions; } 295 auto& tables() { return m_tables; } 296 auto& memories() { return m_memories; } 297 auto& globals() { return m_globals; } 298 auto& elements() { return m_elements; } 299 auto& datas() { return m_datas; } 300 auto& exports() { return m_exports; } 301 302private: 303 Vector<FunctionType> m_types; 304 Vector<FunctionAddress> m_functions; 305 Vector<TableAddress> m_tables; 306 Vector<MemoryAddress> m_memories; 307 Vector<GlobalAddress> m_globals; 308 Vector<ElementAddress> m_elements; 309 Vector<DataAddress> m_datas; 310 Vector<ExportInstance> m_exports; 311}; 312 313class WasmFunction { 314public: 315 explicit WasmFunction(FunctionType const& type, ModuleInstance const& module, Module::Function const& code) 316 : m_type(type) 317 , m_module(module) 318 , m_code(code) 319 { 320 } 321 322 auto& type() const { return m_type; } 323 auto& module() const { return m_module; } 324 auto& code() const { return m_code; } 325 326private: 327 FunctionType m_type; 328 ModuleInstance const& m_module; 329 Module::Function const& m_code; 330}; 331 332class HostFunction { 333public: 334 explicit HostFunction(AK::Function<Result(Configuration&, Vector<Value>&)> function, FunctionType const& type) 335 : m_function(move(function)) 336 , m_type(type) 337 { 338 } 339 340 auto& function() { return m_function; } 341 auto& type() const { return m_type; } 342 343private: 344 AK::Function<Result(Configuration&, Vector<Value>&)> m_function; 345 FunctionType m_type; 346}; 347 348using FunctionInstance = Variant<WasmFunction, HostFunction>; 349 350class TableInstance { 351public: 352 explicit TableInstance(TableType const& type, Vector<Optional<Reference>> elements) 353 : m_elements(move(elements)) 354 , m_type(type) 355 { 356 } 357 358 auto& elements() const { return m_elements; } 359 auto& elements() { return m_elements; } 360 auto& type() const { return m_type; } 361 362 bool grow(size_t size_to_grow, Reference const& fill_value) 363 { 364 if (size_to_grow == 0) 365 return true; 366 auto new_size = m_elements.size() + size_to_grow; 367 if (auto max = m_type.limits().max(); max.has_value()) { 368 if (max.value() < new_size) 369 return false; 370 } 371 auto previous_size = m_elements.size(); 372 if (m_elements.try_resize(new_size).is_error()) 373 return false; 374 for (size_t i = previous_size; i < m_elements.size(); ++i) 375 m_elements[i] = fill_value; 376 return true; 377 } 378 379private: 380 Vector<Optional<Reference>> m_elements; 381 TableType const& m_type; 382}; 383 384class MemoryInstance { 385public: 386 static ErrorOr<MemoryInstance> create(MemoryType const& type) 387 { 388 MemoryInstance instance { type }; 389 390 if (!instance.grow(type.limits().min() * Constants::page_size)) 391 return Error::from_string_literal("Failed to grow to requested size"); 392 393 return { move(instance) }; 394 } 395 396 auto& type() const { return m_type; } 397 auto size() const { return m_size; } 398 auto& data() const { return m_data; } 399 auto& data() { return m_data; } 400 401 bool grow(size_t size_to_grow) 402 { 403 if (size_to_grow == 0) 404 return true; 405 u64 new_size = m_data.size() + size_to_grow; 406 // Can't grow past 2^16 pages. 407 if (new_size >= Constants::page_size * 65536) 408 return false; 409 if (auto max = m_type.limits().max(); max.has_value()) { 410 if (max.value() * Constants::page_size < new_size) 411 return false; 412 } 413 auto previous_size = m_size; 414 if (m_data.try_resize(new_size).is_error()) 415 return false; 416 m_size = new_size; 417 // The spec requires that we zero out everything on grow 418 __builtin_memset(m_data.offset_pointer(previous_size), 0, size_to_grow); 419 return true; 420 } 421 422private: 423 explicit MemoryInstance(MemoryType const& type) 424 : m_type(type) 425 { 426 } 427 428 MemoryType const& m_type; 429 size_t m_size { 0 }; 430 ByteBuffer m_data; 431}; 432 433class GlobalInstance { 434public: 435 explicit GlobalInstance(Value value, bool is_mutable) 436 : m_mutable(is_mutable) 437 , m_value(move(value)) 438 { 439 } 440 441 auto is_mutable() const { return m_mutable; } 442 auto& value() const { return m_value; } 443 GlobalType type() const { return { m_value.type(), is_mutable() }; } 444 void set_value(Value value) 445 { 446 VERIFY(is_mutable()); 447 m_value = move(value); 448 } 449 450private: 451 bool m_mutable { false }; 452 Value m_value; 453}; 454 455class DataInstance { 456public: 457 explicit DataInstance(Vector<u8> data) 458 : m_data(move(data)) 459 { 460 } 461 462 size_t size() const { return m_data.size(); } 463 464 Vector<u8>& data() { return m_data; } 465 Vector<u8> const& data() const { return m_data; } 466 467private: 468 Vector<u8> m_data; 469}; 470 471class ElementInstance { 472public: 473 explicit ElementInstance(ValueType type, Vector<Reference> references) 474 : m_type(move(type)) 475 , m_references(move(references)) 476 { 477 } 478 479 auto& type() const { return m_type; } 480 auto& references() const { return m_references; } 481 482private: 483 ValueType m_type; 484 Vector<Reference> m_references; 485}; 486 487class Store { 488public: 489 Store() = default; 490 491 Optional<FunctionAddress> allocate(ModuleInstance& module, Module::Function const& function); 492 Optional<FunctionAddress> allocate(HostFunction&&); 493 Optional<TableAddress> allocate(TableType const&); 494 Optional<MemoryAddress> allocate(MemoryType const&); 495 Optional<DataAddress> allocate_data(Vector<u8>); 496 Optional<GlobalAddress> allocate(GlobalType const&, Value); 497 Optional<ElementAddress> allocate(ValueType const&, Vector<Reference>); 498 499 FunctionInstance* get(FunctionAddress); 500 TableInstance* get(TableAddress); 501 MemoryInstance* get(MemoryAddress); 502 GlobalInstance* get(GlobalAddress); 503 DataInstance* get(DataAddress); 504 ElementInstance* get(ElementAddress); 505 506private: 507 Vector<FunctionInstance> m_functions; 508 Vector<TableInstance> m_tables; 509 Vector<MemoryInstance> m_memories; 510 Vector<GlobalInstance> m_globals; 511 Vector<ElementInstance> m_elements; 512 Vector<DataInstance> m_datas; 513}; 514 515class Label { 516public: 517 explicit Label(size_t arity, InstructionPointer continuation) 518 : m_arity(arity) 519 , m_continuation(continuation) 520 { 521 } 522 523 auto continuation() const { return m_continuation; } 524 auto arity() const { return m_arity; } 525 526private: 527 size_t m_arity { 0 }; 528 InstructionPointer m_continuation { 0 }; 529}; 530 531class Frame { 532public: 533 explicit Frame(ModuleInstance const& module, Vector<Value> locals, Expression const& expression, size_t arity) 534 : m_module(module) 535 , m_locals(move(locals)) 536 , m_expression(expression) 537 , m_arity(arity) 538 { 539 } 540 541 auto& module() const { return m_module; } 542 auto& locals() const { return m_locals; } 543 auto& locals() { return m_locals; } 544 auto& expression() const { return m_expression; } 545 auto arity() const { return m_arity; } 546 547private: 548 ModuleInstance const& m_module; 549 Vector<Value> m_locals; 550 Expression const& m_expression; 551 size_t m_arity { 0 }; 552}; 553 554class Stack { 555public: 556 using EntryType = Variant<Value, Label, Frame>; 557 Stack() = default; 558 559 [[nodiscard]] ALWAYS_INLINE bool is_empty() const { return m_data.is_empty(); } 560 ALWAYS_INLINE void push(EntryType entry) { m_data.append(move(entry)); } 561 ALWAYS_INLINE auto pop() { return m_data.take_last(); } 562 ALWAYS_INLINE auto& peek() const { return m_data.last(); } 563 ALWAYS_INLINE auto& peek() { return m_data.last(); } 564 565 ALWAYS_INLINE auto size() const { return m_data.size(); } 566 ALWAYS_INLINE auto& entries() const { return m_data; } 567 ALWAYS_INLINE auto& entries() { return m_data; } 568 569private: 570 Vector<EntryType, 1024> m_data; 571}; 572 573using InstantiationResult = AK::Result<NonnullOwnPtr<ModuleInstance>, InstantiationError>; 574 575class AbstractMachine { 576public: 577 explicit AbstractMachine() = default; 578 579 // Validate a module; permanently sets the module's validity status. 580 ErrorOr<void, ValidationError> validate(Module&); 581 // Load and instantiate a module, and link it into this interpreter. 582 InstantiationResult instantiate(Module const&, Vector<ExternValue>); 583 Result invoke(FunctionAddress, Vector<Value>); 584 Result invoke(Interpreter&, FunctionAddress, Vector<Value>); 585 586 auto& store() const { return m_store; } 587 auto& store() { return m_store; } 588 589 void enable_instruction_count_limit() { m_should_limit_instruction_count = true; } 590 591private: 592 Optional<InstantiationError> allocate_all_initial_phase(Module const&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values); 593 Optional<InstantiationError> allocate_all_final_phase(Module const&, ModuleInstance&, Vector<Vector<Reference>>& elements); 594 Store m_store; 595 bool m_should_limit_instruction_count { false }; 596}; 597 598class Linker { 599public: 600 struct Name { 601 DeprecatedString module; 602 DeprecatedString name; 603 ImportSection::Import::ImportDesc type; 604 }; 605 606 explicit Linker(Module const& module) 607 : m_module(module) 608 { 609 } 610 611 // Link a module, the import 'module name' is ignored with this. 612 void link(ModuleInstance const&); 613 614 // Link a bunch of qualified values, also matches 'module name'. 615 void link(HashMap<Name, ExternValue> const&); 616 617 auto& unresolved_imports() 618 { 619 populate(); 620 return m_unresolved_imports; 621 } 622 623 AK::Result<Vector<ExternValue>, LinkError> finish(); 624 625private: 626 void populate(); 627 628 Module const& m_module; 629 HashMap<Name, ExternValue> m_resolved_imports; 630 HashTable<Name> m_unresolved_imports; 631 Vector<Name> m_ordered_imports; 632 Optional<LinkError> m_error; 633}; 634 635} 636 637template<> 638struct AK::Traits<Wasm::Linker::Name> : public AK::GenericTraits<Wasm::Linker::Name> { 639 static constexpr bool is_trivial() { return false; } 640 static unsigned hash(Wasm::Linker::Name const& entry) { return pair_int_hash(entry.module.hash(), entry.name.hash()); } 641 static bool equals(Wasm::Linker::Name const& a, Wasm::Linker::Name const& b) { return a.name == b.name && a.module == b.module; } 642};