/src/serenity/Userland/Libraries/LibWeb/WebAssembly/Table.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> |
3 | | * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <LibJS/Runtime/Realm.h> |
9 | | #include <LibJS/Runtime/VM.h> |
10 | | #include <LibWasm/Types.h> |
11 | | #include <LibWeb/Bindings/Intrinsics.h> |
12 | | #include <LibWeb/Bindings/TablePrototype.h> |
13 | | #include <LibWeb/WebAssembly/Table.h> |
14 | | #include <LibWeb/WebAssembly/WebAssembly.h> |
15 | | |
16 | | namespace Web::WebAssembly { |
17 | | |
18 | | JS_DEFINE_ALLOCATOR(Table); |
19 | | |
20 | | static Wasm::ValueType table_kind_to_value_type(Bindings::TableKind kind) |
21 | 0 | { |
22 | 0 | switch (kind) { |
23 | 0 | case Bindings::TableKind::Externref: |
24 | 0 | return Wasm::ValueType { Wasm::ValueType::ExternReference }; |
25 | 0 | case Bindings::TableKind::Anyfunc: |
26 | 0 | return Wasm::ValueType { Wasm::ValueType::FunctionReference }; |
27 | 0 | } |
28 | | |
29 | 0 | VERIFY_NOT_REACHED(); |
30 | 0 | } |
31 | | |
32 | | static JS::ThrowCompletionOr<Wasm::Value> value_to_reference(JS::VM& vm, JS::Value value, Wasm::ValueType const& reference_type) |
33 | 0 | { |
34 | 0 | if (value.is_undefined()) |
35 | 0 | return Wasm::Value(); |
36 | 0 | return Detail::to_webassembly_value(vm, value, reference_type); |
37 | 0 | } |
38 | | |
39 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<Table>> Table::construct_impl(JS::Realm& realm, TableDescriptor& descriptor, JS::Value value) |
40 | 0 | { |
41 | 0 | auto& vm = realm.vm(); |
42 | |
|
43 | 0 | auto reference_type = table_kind_to_value_type(descriptor.element); |
44 | 0 | auto reference_value = TRY(value_to_reference(vm, value, reference_type)); |
45 | | |
46 | 0 | Wasm::Limits limits { descriptor.initial, move(descriptor.maximum) }; |
47 | 0 | Wasm::TableType table_type { reference_type, move(limits) }; |
48 | |
|
49 | 0 | auto& cache = Detail::get_cache(realm); |
50 | 0 | auto address = cache.abstract_machine().store().allocate(table_type); |
51 | 0 | if (!address.has_value()) |
52 | 0 | return vm.throw_completion<JS::TypeError>("Wasm Table allocation failed"sv); |
53 | | |
54 | 0 | auto const& reference = reference_value.to<Wasm::Reference>(); |
55 | 0 | auto& table = *cache.abstract_machine().store().get(*address); |
56 | 0 | for (auto& element : table.elements()) |
57 | 0 | element = reference; |
58 | |
|
59 | 0 | return vm.heap().allocate<Table>(realm, realm, *address); |
60 | 0 | } |
61 | | |
62 | | Table::Table(JS::Realm& realm, Wasm::TableAddress address) |
63 | 0 | : Bindings::PlatformObject(realm) |
64 | 0 | , m_address(address) |
65 | 0 | { |
66 | 0 | } |
67 | | |
68 | | void Table::initialize(JS::Realm& realm) |
69 | 0 | { |
70 | 0 | Base::initialize(realm); |
71 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(Table, WebAssembly.Table); |
72 | 0 | } |
73 | | |
74 | | // https://webassembly.github.io/spec/js-api/#dom-table-grow |
75 | | WebIDL::ExceptionOr<u32> Table::grow(u32 delta, JS::Value value) |
76 | 0 | { |
77 | 0 | auto& vm = this->vm(); |
78 | |
|
79 | 0 | auto& cache = Detail::get_cache(realm()); |
80 | 0 | auto* table = cache.abstract_machine().store().get(address()); |
81 | 0 | if (!table) |
82 | 0 | return vm.throw_completion<JS::RangeError>("Could not find the memory table to grow"sv); |
83 | | |
84 | 0 | auto initial_size = table->elements().size(); |
85 | |
|
86 | 0 | auto reference_value = TRY(value_to_reference(vm, value, table->type().element_type())); |
87 | 0 | auto const& reference = reference_value.to<Wasm::Reference>(); |
88 | |
|
89 | 0 | if (!table->grow(delta, reference)) |
90 | 0 | return vm.throw_completion<JS::RangeError>("Failed to grow table"sv); |
91 | | |
92 | 0 | return initial_size; |
93 | 0 | } |
94 | | |
95 | | // https://webassembly.github.io/spec/js-api/#dom-table-get |
96 | | WebIDL::ExceptionOr<JS::Value> Table::get(u32 index) const |
97 | 0 | { |
98 | 0 | auto& vm = this->vm(); |
99 | |
|
100 | 0 | auto& cache = Detail::get_cache(realm()); |
101 | 0 | auto* table = cache.abstract_machine().store().get(address()); |
102 | 0 | if (!table) |
103 | 0 | return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv); |
104 | | |
105 | 0 | if (table->elements().size() <= index) |
106 | 0 | return vm.throw_completion<JS::RangeError>("Table element index out of range"sv); |
107 | | |
108 | 0 | auto& ref = table->elements()[index]; |
109 | |
|
110 | 0 | Wasm::Value wasm_value { ref }; |
111 | 0 | return Detail::to_js_value(vm, wasm_value, table->type().element_type()); |
112 | 0 | } |
113 | | |
114 | | // https://webassembly.github.io/spec/js-api/#dom-table-set |
115 | | WebIDL::ExceptionOr<void> Table::set(u32 index, JS::Value value) |
116 | 0 | { |
117 | 0 | auto& vm = this->vm(); |
118 | |
|
119 | 0 | auto& cache = Detail::get_cache(realm()); |
120 | 0 | auto* table = cache.abstract_machine().store().get(address()); |
121 | 0 | if (!table) |
122 | 0 | return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv); |
123 | | |
124 | 0 | if (table->elements().size() <= index) |
125 | 0 | return vm.throw_completion<JS::RangeError>("Table element index out of range"sv); |
126 | | |
127 | 0 | auto reference_value = TRY(value_to_reference(vm, value, table->type().element_type())); |
128 | 0 | auto const& reference = reference_value.to<Wasm::Reference>(); |
129 | |
|
130 | 0 | table->elements()[index] = reference; |
131 | |
|
132 | 0 | return {}; |
133 | 0 | } |
134 | | |
135 | | // https://webassembly.github.io/spec/js-api/#dom-table-length |
136 | | WebIDL::ExceptionOr<u32> Table::length() const |
137 | 0 | { |
138 | 0 | auto& vm = this->vm(); |
139 | |
|
140 | 0 | auto& cache = Detail::get_cache(realm()); |
141 | 0 | auto* table = cache.abstract_machine().store().get(address()); |
142 | 0 | if (!table) |
143 | 0 | return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv); |
144 | | |
145 | 0 | return table->elements().size(); |
146 | 0 | } |
147 | | |
148 | | } |