Skip to content

Commit ebcd539

Browse files
Use ImportResolver for table imports
1 parent a8ccf99 commit ebcd539

File tree

10 files changed

+157
-241
lines changed

10 files changed

+157
-241
lines changed

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: 16 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,10 @@ 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+
// TODO: new type for TableType or just re-use the existing one?
137+
virtual RuntimeTable* getTableOrNull(ImportNames name,
138+
const Table& type) const = 0;
134139
};
135140

136141
// Looks up imports from the given `linkedInstances`.
@@ -151,6 +156,17 @@ class LinkedInstancesImportResolver : public ImportResolver {
151156
return instance->getExportedGlobalOrNull(name.name);
152157
}
153158

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

src/ir/runtime-table.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
// TODO: constructor for initial contents?
16+
RuntimeTable(Table table_, std::function<void(std::string_view s)> trap_)
17+
: tableMeta_(table_), trap(trap_) {}
18+
19+
void set(std::size_t i, Literal l);
20+
21+
Literal get(std::size_t i) const;
22+
23+
// Returns nullopt if the table grew beyond the max possible size.
24+
[[nodiscard]] std::optional<std::size_t> grow(std::size_t delta,
25+
Literal fill);
26+
27+
std::size_t size() const { return table.size(); }
28+
29+
const Table* tableMeta() const { return &tableMeta_; }
30+
31+
private:
32+
const Table tableMeta_;
33+
std::vector<Literal> table;
34+
std::function<void(std::string_view)> trap;
35+
};
36+
37+
} // namespace wasm
38+
39+
#endif // wasm_ir_runtime_table_h

src/shell-interface.h

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ namespace wasm {
3434
// An exception emitted when exit() is called.
3535
struct ExitException {};
3636

37-
// An exception emitted when a wasm trap occurs.
38-
struct TrapException {};
39-
4037
// An exception emitted when a host limitation is hit. (These are not wasm traps
4138
// as they are not in the spec; for example, the spec has no limit on how much
4239
// GC memory may be allocated, but hosts have limits.)
@@ -93,7 +90,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
9390
};
9491

9592
std::map<Name, Memory> memories;
96-
std::unordered_map<Name, std::vector<Literal>> tables;
9793
std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances;
9894

9995
ShellExternalInterface(
@@ -125,8 +121,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
125121
shellMemory.resize(memory->initial * wasm::Memory::kPageSize);
126122
memories[memory->name] = shellMemory;
127123
});
128-
ModuleUtils::iterDefinedTables(
129-
wasm, [&](Table* table) { tables[table->name].resize(table->initial); });
130124
}
131125

132126
Literal getImportedFunction(Function* import) override {
@@ -255,35 +249,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
255249
auto& memory = it->second;
256250
memory.set<std::array<uint8_t, 16>>(addr, value);
257251
}
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-
287252
bool
288253
growMemory(Name memoryName, Address /*oldSize*/, Address newSize) override {
289254
// Apply a reasonable limit on memory size, 1GB, to avoid DOS on the
@@ -299,20 +264,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
299264
memory.resize(newSize);
300265
return true;
301266
}
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-
316267
void trap(std::string_view why) override {
317268
std::cout << "[trap " << why << "]\n";
318269
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());

src/tools/wasm-ctor-eval.cpp

Lines changed: 8 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ class EvallingImportResolver : public ImportResolver {
8080
return &stubLiteral;
8181
}
8282

83+
RuntimeTable* getTableOrNull(ImportNames name,
84+
const Table& type) const override {
85+
throw FailToEvalException{"Imported table access."};
86+
}
87+
8388
private:
8489
mutable Literals stubLiteral;
8590
};
@@ -156,17 +161,6 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) {
156161
}
157162
});
158163

159-
// create tables with similar initial and max values
160-
ModuleUtils::iterImportedTables(wasm, [&](Table* table) {
161-
if (table->module == env->name) {
162-
auto* copied = ModuleUtils::copyTable(table, *env);
163-
copied->module = Name();
164-
copied->base = Name();
165-
env->addExport(Builder(*env).makeExport(
166-
table->base, copied->name, ExternalKind::Table));
167-
}
168-
});
169-
170164
// create an exported memory with the same initial and max size
171165
ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) {
172166
if (memory->module == env->name) {
@@ -316,68 +310,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
316310
}
317311

318312
// We assume the table is not modified FIXME
319-
Literal tableLoad(Name tableName, Address index) override {
320-
auto* table = wasm->getTableOrNull(tableName);
321-
if (!table) {
322-
throw FailToEvalException("tableLoad on non-existing table");
323-
}
324-
325-
// Look through the segments and find the value. Segments can overlap,
326-
// so we want the last one.
327-
Expression* value = nullptr;
328-
for (auto& segment : wasm->elementSegments) {
329-
if (segment->table != tableName) {
330-
continue;
331-
}
332-
333-
Index start;
334-
// look for the index in this segment. if it has a constant offset, we
335-
// look in the proper range. if it instead gets a global, we rely on the
336-
// fact that when not dynamically linking then the table is loaded at
337-
// offset 0.
338-
if (auto* c = segment->offset->dynCast<Const>()) {
339-
start = c->value.getInteger();
340-
} else if (segment->offset->is<GlobalGet>()) {
341-
start = 0;
342-
} else {
343-
// wasm spec only allows const and global.get there
344-
WASM_UNREACHABLE("invalid expr type");
345-
}
346-
auto end = start + segment->data.size();
347-
if (start <= index && index < end) {
348-
value = segment->data[index - start];
349-
}
350-
}
351-
352-
if (!value) {
353-
// No segment had a value for this.
354-
return Literal::makeNull(HeapTypes::func);
355-
}
356-
if (!Properties::isConstantExpression(value)) {
357-
throw FailToEvalException("tableLoad of non-literal");
358-
}
359-
if (auto* r = value->dynCast<RefFunc>()) {
360-
return instance->makeFuncData(r->func, r->type);
361-
}
362-
return Properties::getLiteral(value);
363-
}
364-
365-
Index tableSize(Name tableName) override {
366-
// See tableLoad above, we assume the table is not modified FIXME
367-
return wasm->getTableOrNull(tableName)->initial;
368-
}
369-
370-
// called during initialization
371-
void
372-
tableStore(Name tableName, Address index, const Literal& value) override {
373-
// We allow stores to the table during initialization, but not after, as we
374-
// assume the table does not change at runtime.
375-
// TODO: Allow table changes by updating the table later like we do with the
376-
// memory, by tracking and serializing them.
377-
if (instanceInitialized) {
378-
throw FailToEvalException("tableStore after init: TODO");
379-
}
380-
}
381313

382314
int8_t load8s(Address addr, Name memoryName) override {
383315
return doLoad<int8_t>(addr, memoryName);
@@ -431,13 +363,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
431363
throw FailToEvalException("grow memory");
432364
}
433365

434-
bool growTable(Name /*name*/,
435-
const Literal& /*value*/,
436-
Index /*oldSize*/,
437-
Index /*newSize*/) override {
438-
throw FailToEvalException("grow table");
439-
}
440-
441366
void trap(std::string_view why) override {
442367
throw FailToEvalException(std::string("trap: ") + std::string(why));
443368
}
@@ -1145,6 +1070,9 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance,
11451070
std::cout << " ...stopping due to non-constant func\n";
11461071
}
11471072
break;
1073+
} catch (TrapException trap) {
1074+
std::cout << " ...stopping due to trap";
1075+
break;
11481076
}
11491077

11501078
if (flow.breakTo == NONCONSTANT_FLOW) {

0 commit comments

Comments
 (0)