Skip to content

Commit f30f8c6

Browse files
Use ImportResolver for table imports
1 parent 5732607 commit f30f8c6

File tree

9 files changed

+346
-248
lines changed

9 files changed

+346
-248
lines changed

src/interpreter/exception.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef wasm_interpreter_exception_h
2+
#define wasm_interpreter_exception_h
3+
4+
namespace wasm {
5+
6+
// An exception emitted when exit() is called.
7+
struct ExitException {};
8+
9+
// An exception emitted when a wasm trap occurs.
10+
struct TrapException {};
11+
12+
// An exception emitted when a host limitation is hit. (These are not wasm traps
13+
// as they are not in the spec; for example, the spec has no limit on how much
14+
// GC memory may be allocated, but hosts have limits.)
15+
struct HostLimitException {};
16+
17+
} // namespace wasm
18+
19+
#endif // wasm_interpreter_exception_h

src/ir/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(ir_SOURCES
2020
public-type-validator.cpp
2121
ReFinalize.cpp
2222
return-utils.cpp
23+
runtime-table.cpp
2324
stack-utils.cpp
2425
table-utils.cpp
2526
type-updating.cpp

src/ir/import-utils.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define wasm_ir_import_h
1919

2020
#include "ir/import-name.h"
21+
#include "ir/runtime-table.h"
2122
#include "literal.h"
2223
#include "wasm.h"
2324

@@ -131,6 +132,11 @@ class ImportResolver {
131132
// Returns null if the `name` wasn't found. The returned Literals* lives as
132133
// long as the ImportResolver instance.
133134
virtual Literals* getGlobalOrNull(ImportNames name, Type type) const = 0;
135+
136+
// Returns null if the `name` wasn't found. The returned RuntimeTable* lives
137+
// as long as the ImportResolver instance.
138+
virtual RuntimeTable* getTableOrNull(ImportNames name,
139+
const Table& type) const = 0;
134140
};
135141

136142
// Looks up imports from the given `linkedInstances`.
@@ -151,6 +157,17 @@ class LinkedInstancesImportResolver : public ImportResolver {
151157
return instance->getExportedGlobalOrNull(name.name);
152158
}
153159

160+
RuntimeTable* getTableOrNull(ImportNames name,
161+
const Table& type) const override {
162+
auto it = linkedInstances.find(name.module);
163+
if (it == linkedInstances.end()) {
164+
return nullptr;
165+
}
166+
167+
ModuleRunnerType* instance = it->second.get();
168+
return instance->getExportedTableOrNull(name.name);
169+
}
170+
154171
private:
155172
const std::map<Name, std::shared_ptr<ModuleRunnerType>> linkedInstances;
156173
};

src/ir/runtime-table.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include "ir/runtime-table.h"
2+
#include "interpreter/exception.h"
3+
#include "support/stdckdint.h"
4+
#include "wasm-limits.h"
5+
6+
namespace wasm {
7+
8+
namespace {
9+
10+
[[noreturn]] void trap(std::string_view reason) {
11+
// Print so lit tests can check this.
12+
std::cout << "[trap " << reason << "]\n";
13+
throw TrapException{};
14+
}
15+
16+
} // namespace
17+
18+
void RealRuntimeTable::set(std::size_t i, Literal l) {
19+
if (i >= table.size()) {
20+
trap("RuntimeTable::set out of bounds");
21+
WASM_UNREACHABLE("trapped");
22+
}
23+
24+
table[i] = std::move(l);
25+
}
26+
27+
Literal RealRuntimeTable::get(std::size_t i) const {
28+
if (i >= table.size()) {
29+
trap("out of bounds table access");
30+
WASM_UNREACHABLE("trapped");
31+
}
32+
33+
return table[i];
34+
}
35+
36+
std::optional<std::size_t> RealRuntimeTable::grow(std::size_t delta,
37+
Literal fill) {
38+
std::size_t newSize;
39+
if (std::ckd_add(&newSize, table.size(), delta)) {
40+
return std::nullopt;
41+
}
42+
43+
if (newSize > WebLimitations::MaxTableSize || newSize > tableMeta_.max) {
44+
return std::nullopt;
45+
}
46+
47+
std::size_t oldSize = table.size();
48+
table.resize(newSize, fill);
49+
return oldSize;
50+
}
51+
52+
} // namespace wasm

src/ir/runtime-table.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef wasm_ir_runtime_table_h
2+
#define wasm_ir_runtime_table_h
3+
4+
#include <stddef.h>
5+
#include <vector>
6+
7+
#include "literal.h"
8+
#include "wasm.h"
9+
10+
namespace wasm {
11+
12+
// Traps on out of bounds access
13+
class RuntimeTable {
14+
public:
15+
virtual ~RuntimeTable() = default;
16+
17+
virtual void set(std::size_t i, Literal l) = 0;
18+
19+
virtual Literal get(std::size_t i) const = 0;
20+
21+
// Returns nullopt if the table grew beyond the max possible size.
22+
[[nodiscard]] virtual std::optional<std::size_t> grow(std::size_t delta,
23+
Literal fill) = 0;
24+
25+
virtual std::size_t size() const = 0;
26+
27+
virtual const Table* tableMeta() const = 0;
28+
};
29+
30+
class RealRuntimeTable : public RuntimeTable {
31+
public:
32+
RealRuntimeTable(Literal initial, Table table_) : tableMeta_(table_) {
33+
table.resize(tableMeta_.initial, initial);
34+
}
35+
36+
RealRuntimeTable(const RealRuntimeTable&) = delete;
37+
RealRuntimeTable& operator=(const RealRuntimeTable&) = delete;
38+
39+
void set(std::size_t i, Literal l) override;
40+
41+
Literal get(std::size_t i) const override;
42+
43+
std::optional<std::size_t> grow(std::size_t delta, Literal fill) override;
44+
45+
std::size_t size() const override { return table.size(); }
46+
47+
const Table* tableMeta() const override { return &tableMeta_; }
48+
49+
private:
50+
const Table tableMeta_;
51+
std::vector<Literal> table;
52+
};
53+
54+
} // namespace wasm
55+
56+
#endif // wasm_ir_runtime_table_h

src/shell-interface.h

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define wasm_shell_interface_h
2323

2424
#include "asmjs/shared-constants.h"
25+
#include "interpreter/exception.h"
2526
#include "ir/module-utils.h"
2627
#include "shared-constants.h"
2728
#include "support/name.h"
@@ -31,17 +32,6 @@
3132

3233
namespace wasm {
3334

34-
// An exception emitted when exit() is called.
35-
struct ExitException {};
36-
37-
// An exception emitted when a wasm trap occurs.
38-
struct TrapException {};
39-
40-
// An exception emitted when a host limitation is hit. (These are not wasm traps
41-
// as they are not in the spec; for example, the spec has no limit on how much
42-
// GC memory may be allocated, but hosts have limits.)
43-
struct HostLimitException {};
44-
4535
struct ShellExternalInterface : ModuleRunner::ExternalInterface {
4636
// The underlying memory can be accessed through unaligned pointers which
4737
// isn't well-behaved in C++. WebAssembly nonetheless expects it to behave
@@ -93,7 +83,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
9383
};
9484

9585
std::map<Name, Memory> memories;
96-
std::unordered_map<Name, std::vector<Literal>> tables;
9786
std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances;
9887

9988
ShellExternalInterface(
@@ -125,8 +114,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
125114
shellMemory.resize(memory->initial * wasm::Memory::kPageSize);
126115
memories[memory->name] = shellMemory;
127116
});
128-
ModuleUtils::iterDefinedTables(
129-
wasm, [&](Table* table) { tables[table->name].resize(table->initial); });
130117
}
131118

132119
Literal getImportedFunction(Function* import) override {
@@ -255,35 +242,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
255242
auto& memory = it->second;
256243
memory.set<std::array<uint8_t, 16>>(addr, value);
257244
}
258-
259-
Index tableSize(Name tableName) override {
260-
return (Index)tables[tableName].size();
261-
}
262-
263-
void
264-
tableStore(Name tableName, Address index, const Literal& entry) override {
265-
auto& table = tables[tableName];
266-
if (index >= table.size()) {
267-
trap("out of bounds table access");
268-
} else {
269-
table[index] = entry;
270-
}
271-
}
272-
273-
Literal tableLoad(Name tableName, Address index) override {
274-
auto it = tables.find(tableName);
275-
if (it == tables.end()) {
276-
trap("tableGet on non-existing table");
277-
}
278-
279-
auto& table = it->second;
280-
if (index >= table.size()) {
281-
trap("out of bounds table access");
282-
}
283-
284-
return table[index];
285-
}
286-
287245
bool
288246
growMemory(Name memoryName, Address /*oldSize*/, Address newSize) override {
289247
// Apply a reasonable limit on memory size, 1GB, to avoid DOS on the
@@ -299,20 +257,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
299257
memory.resize(newSize);
300258
return true;
301259
}
302-
303-
bool growTable(Name name,
304-
const Literal& value,
305-
Index /*oldSize*/,
306-
Index newSize) override {
307-
// Apply a reasonable limit on table size, 1GB, to avoid DOS on the
308-
// interpreter.
309-
if (newSize > 1024 * 1024 * 1024) {
310-
return false;
311-
}
312-
tables[name].resize(newSize, value);
313-
return true;
314-
}
315-
316260
void trap(std::string_view why) override {
317261
std::cout << "[trap " << why << "]\n";
318262
throw TrapException();

src/tools/execution-results.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,21 @@ struct LoggingExternalInterface : public ShellExternalInterface {
142142
throwJSException();
143143
}
144144
auto index = arguments[0].getUnsigned();
145-
if (index >= tables[exportedTable].size()) {
145+
auto* table = instance->allTables[exportedTable];
146+
if (index >= table->size()) {
146147
throwJSException();
147148
}
148-
return {tableLoad(exportedTable, index)};
149+
return table->get(index);
149150
} else if (import->base == "table-set") {
150151
if (!exportedTable) {
151152
throwJSException();
152153
}
153154
auto index = arguments[0].getUnsigned();
154-
if (index >= tables[exportedTable].size()) {
155+
auto* table = instance->allTables[exportedTable];
156+
if (index >= table->size()) {
155157
throwJSException();
156158
}
157-
tableStore(exportedTable, index, arguments[1]);
159+
table->set(index, arguments[1]);
158160
return {};
159161
} else if (import->base == "call-export") {
160162
callExportAsJS(arguments[0].geti32());

0 commit comments

Comments
 (0)