diff options
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r-- | src/wasm-interpreter.h | 232 |
1 files changed, 146 insertions, 86 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 37bebdf6b..8c772a96e 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2068,6 +2068,8 @@ public: // an imported function or accessing memory. // struct ExternalInterface { + ExternalInterface( + std::map<Name, std::shared_ptr<SubType>> linkedInstances = {}) {} virtual ~ExternalInterface() = default; virtual void init(Module& wasm, SubType& instance) {} virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0; @@ -2241,8 +2243,12 @@ public: // Multivalue ABI support (see push/pop). std::vector<Literals> multiValues; - ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface) - : wasm(wasm), externalInterface(externalInterface) { + ModuleInstanceBase( + Module& wasm, + ExternalInterface* externalInterface, + std::map<Name, std::shared_ptr<SubType>> linkedInstances_ = {}) + : wasm(wasm), externalInterface(externalInterface), + linkedInstances(linkedInstances_) { // import globals from the outside externalInterface->importGlobals(globals, wasm); // prepare memory @@ -2314,19 +2320,24 @@ private: void initializeTableContents() { ModuleUtils::iterActiveElementSegments(wasm, [&](ElementSegment* segment) { - Address offset = - (uint32_t)InitializerExpressionRunner<GlobalManager>(globals, maxDepth) - .visit(segment->offset) - .getSingleValue() - .geti32(); - Function dummyFunc; FunctionScope dummyScope(&dummyFunc, {}); RuntimeExpressionRunner runner(*this, dummyScope, maxDepth); + + Address offset = + (uint32_t)runner.visit(segment->offset).getSingleValue().geti32(); + + Table* table = wasm.getTable(segment->table); + ExternalInterface* extInterface = externalInterface; + Name tableName = segment->table; + if (table->imported()) { + auto inst = linkedInstances.at(table->module); + extInterface = inst->externalInterface; + tableName = inst->wasm.getExport(table->base)->value; + } for (Index i = 0; i < segment->data.size(); ++i) { Flow ret = runner.visit(segment->data[i]); - externalInterface->tableStore( - segment->table, offset + i, ret.getSingleValue()); + extInterface->tableStore(tableName, offset + i, ret.getSingleValue()); } }); } @@ -2408,6 +2419,28 @@ private: // Stack of <caught exception, caught catch's try label> SmallVector<std::pair<WasmException, Name>, 4> exceptionStack; + protected: + // Returns the instance that defines the memory used by this one. + SubType* getMemoryInstance() { + if (instance.wasm.memory.imported()) { + return instance.linkedInstances.at(instance.wasm.memory.module).get(); + } else { + return static_cast<SubType*>(&instance); + } + } + + // Returns a reference to the current value of a potentially imported global + Literals& getGlobal(Name name) { + auto* global = instance.wasm.getGlobal(name); + if (global->imported()) { + auto inst = instance.linkedInstances.at(global->module); + Export* globalExport = inst->wasm.getExport(global->base); + return inst->globals[globalExport->value]; + } else { + return instance.globals[name]; + } + } + public: RuntimeExpressionRunner(ModuleInstanceBase& instance, FunctionScope& scope, @@ -2450,10 +2483,26 @@ private: if (target.breaking()) { return target; } + Index index = target.getSingleValue().geti32(); Type type = curr->isReturn ? scope.function->sig.results : curr->type; - Flow ret = instance.externalInterface->callTable( - curr->table, index, curr->sig, arguments, type, *instance.self()); + + Flow ret; + auto* table = instance.wasm.getTable(curr->table); + if (table->imported()) { + auto inst = instance.linkedInstances.at(table->module); + Export* tableExport = inst->wasm.getExport(table->base); + ret = inst->externalInterface->callTable(tableExport->value, + index, + curr->sig, + arguments, + type, + *instance.self()); + } else { + ret = instance.externalInterface->callTable( + curr->table, index, curr->sig, arguments, type, *instance.self()); + } + // TODO: make this a proper tail call (return first) if (curr->isReturn) { ret.breakTo = RETURN_FLOW; @@ -2518,9 +2567,7 @@ private: NOTE_ENTER("GlobalGet"); auto name = curr->name; NOTE_EVAL1(name); - assert(instance.globals.find(name) != instance.globals.end()); - NOTE_EVAL1(instance.globals[name]); - return instance.globals[name]; + return getGlobal(name); } Flow visitGlobalSet(GlobalSet* curr) { NOTE_ENTER("GlobalSet"); @@ -2531,7 +2578,8 @@ private: } NOTE_EVAL1(name); NOTE_EVAL1(flow.getSingleValue()); - instance.globals[name] = flow.values; + + getGlobal(name) = flow.values; return Flow(); } @@ -2542,11 +2590,12 @@ private: return flow; } NOTE_EVAL1(flow); - auto addr = instance.getFinalAddress(curr, flow.getSingleValue()); + auto* inst = getMemoryInstance(); + auto addr = inst->getFinalAddress(curr, flow.getSingleValue()); if (curr->isAtomic) { - instance.checkAtomicAddress(addr, curr->bytes); + inst->checkAtomicAddress(addr, curr->bytes); } - auto ret = instance.externalInterface->load(curr, addr); + auto ret = inst->externalInterface->load(curr, addr); NOTE_EVAL1(addr); NOTE_EVAL1(ret); return ret; @@ -2561,13 +2610,14 @@ private: if (value.breaking()) { return value; } - auto addr = instance.getFinalAddress(curr, ptr.getSingleValue()); + auto* inst = getMemoryInstance(); + auto addr = inst->getFinalAddress(curr, ptr.getSingleValue()); if (curr->isAtomic) { - instance.checkAtomicAddress(addr, curr->bytes); + inst->checkAtomicAddress(addr, curr->bytes); } NOTE_EVAL1(addr); NOTE_EVAL1(value); - instance.externalInterface->store(curr, addr, value.getSingleValue()); + inst->externalInterface->store(curr, addr, value.getSingleValue()); return Flow(); } @@ -2582,10 +2632,11 @@ private: return value; } NOTE_EVAL1(ptr); - auto addr = instance.getFinalAddress(curr, ptr.getSingleValue()); + auto* inst = getMemoryInstance(); + auto addr = inst->getFinalAddress(curr, ptr.getSingleValue()); NOTE_EVAL1(addr); NOTE_EVAL1(value); - auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type); + auto loaded = inst->doAtomicLoad(addr, curr->bytes, curr->type); NOTE_EVAL1(loaded); auto computed = value.getSingleValue(); switch (curr->op) { @@ -2607,7 +2658,7 @@ private: case RMWXchg: break; } - instance.doAtomicStore(addr, curr->bytes, computed); + inst->doAtomicStore(addr, curr->bytes, computed); return loaded; } Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) { @@ -2625,16 +2676,17 @@ private: if (replacement.breaking()) { return replacement; } - auto addr = instance.getFinalAddress(curr, ptr.getSingleValue()); + auto* inst = getMemoryInstance(); + auto addr = inst->getFinalAddress(curr, ptr.getSingleValue()); expected = Flow(wrapToSmallerSize(expected.getSingleValue(), curr->bytes)); NOTE_EVAL1(addr); NOTE_EVAL1(expected); NOTE_EVAL1(replacement); - auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type); + auto loaded = inst->doAtomicLoad(addr, curr->bytes, curr->type); NOTE_EVAL1(loaded); if (loaded == expected.getSingleValue()) { - instance.doAtomicStore(addr, curr->bytes, replacement.getSingleValue()); + inst->doAtomicStore(addr, curr->bytes, replacement.getSingleValue()); } return loaded; } @@ -2655,9 +2707,10 @@ private: if (timeout.breaking()) { return timeout; } + auto* inst = getMemoryInstance(); auto bytes = curr->expectedType.getByteSize(); - auto addr = instance.getFinalAddress(curr, ptr.getSingleValue(), bytes); - auto loaded = instance.doAtomicLoad(addr, bytes, curr->expectedType); + auto addr = inst->getFinalAddress(curr, ptr.getSingleValue(), bytes); + auto loaded = inst->doAtomicLoad(addr, bytes, curr->expectedType); NOTE_EVAL1(loaded); if (loaded != expected.getSingleValue()) { return Literal(int32_t(1)); // not equal @@ -2678,9 +2731,10 @@ private: if (count.breaking()) { return count; } - auto addr = instance.getFinalAddress(curr, ptr.getSingleValue(), 4); + auto* inst = getMemoryInstance(); + auto addr = inst->getFinalAddress(curr, ptr.getSingleValue(), 4); // Just check TODO actual threads support - instance.checkAtomicAddress(addr, 4); + inst->checkAtomicAddress(addr, 4); return Literal(int32_t(0)); // none woken up } Flow visitSIMDLoad(SIMDLoad* curr) { @@ -2745,20 +2799,21 @@ private: } NOTE_EVAL1(flow); Address src(uint32_t(flow.getSingleValue().geti32())); + auto* inst = getMemoryInstance(); auto loadLane = [&](Address addr) { switch (curr->op) { case Load8x8SVec128: - return Literal(int32_t(instance.externalInterface->load8s(addr))); + return Literal(int32_t(inst->externalInterface->load8s(addr))); case Load8x8UVec128: - return Literal(int32_t(instance.externalInterface->load8u(addr))); + return Literal(int32_t(inst->externalInterface->load8u(addr))); case Load16x4SVec128: - return Literal(int32_t(instance.externalInterface->load16s(addr))); + return Literal(int32_t(inst->externalInterface->load16s(addr))); case Load16x4UVec128: - return Literal(int32_t(instance.externalInterface->load16u(addr))); + return Literal(int32_t(inst->externalInterface->load16u(addr))); case Load32x2SVec128: - return Literal(int64_t(instance.externalInterface->load32s(addr))); + return Literal(int64_t(inst->externalInterface->load32s(addr))); case Load32x2UVec128: - return Literal(int64_t(instance.externalInterface->load32u(addr))); + return Literal(int64_t(inst->externalInterface->load32u(addr))); default: WASM_UNREACHABLE("unexpected op"); } @@ -2767,7 +2822,7 @@ private: auto fillLanes = [&](auto lanes, size_t laneBytes) { for (auto& lane : lanes) { lane = loadLane( - instance.getFinalAddress(curr, Literal(uint32_t(src)), laneBytes)); + inst->getFinalAddress(curr, Literal(uint32_t(src)), laneBytes)); src = Address(uint32_t(src) + laneBytes); } return Literal(lanes); @@ -2799,15 +2854,16 @@ private: return flow; } NOTE_EVAL1(flow); - Address src = instance.getFinalAddress( - curr, flow.getSingleValue(), curr->getMemBytes()); + auto* inst = getMemoryInstance(); + Address src = + inst->getFinalAddress(curr, flow.getSingleValue(), curr->getMemBytes()); auto zero = Literal::makeZero(curr->op == Load32ZeroVec128 ? Type::i32 : Type::i64); if (curr->op == Load32ZeroVec128) { - auto val = Literal(instance.externalInterface->load32u(src)); + auto val = Literal(inst->externalInterface->load32u(src)); return Literal(std::array<Literal, 4>{{val, zero, zero, zero}}); } else { - auto val = Literal(instance.externalInterface->load64u(src)); + auto val = Literal(inst->externalInterface->load64u(src)); return Literal(std::array<Literal, 2>{{val, zero}}); } } @@ -2818,8 +2874,9 @@ private: return flow; } NOTE_EVAL1(flow); - Address addr = instance.getFinalAddress( - curr, flow.getSingleValue(), curr->getMemBytes()); + auto* inst = getMemoryInstance(); + Address addr = + inst->getFinalAddress(curr, flow.getSingleValue(), curr->getMemBytes()); flow = this->visit(curr->vec); if (flow.breaking()) { return flow; @@ -2830,12 +2887,10 @@ private: case Store8LaneVec128: { std::array<Literal, 16> lanes = vec.getLanesUI8x16(); if (curr->isLoad()) { - lanes[curr->index] = - Literal(instance.externalInterface->load8u(addr)); + lanes[curr->index] = Literal(inst->externalInterface->load8u(addr)); return Literal(lanes); } else { - instance.externalInterface->store8(addr, - lanes[curr->index].geti32()); + inst->externalInterface->store8(addr, lanes[curr->index].geti32()); return {}; } } @@ -2844,11 +2899,10 @@ private: std::array<Literal, 8> lanes = vec.getLanesUI16x8(); if (curr->isLoad()) { lanes[curr->index] = - Literal(instance.externalInterface->load16u(addr)); + Literal(inst->externalInterface->load16u(addr)); return Literal(lanes); } else { - instance.externalInterface->store16(addr, - lanes[curr->index].geti32()); + inst->externalInterface->store16(addr, lanes[curr->index].geti32()); return {}; } } @@ -2857,11 +2911,10 @@ private: std::array<Literal, 4> lanes = vec.getLanesI32x4(); if (curr->isLoad()) { lanes[curr->index] = - Literal(instance.externalInterface->load32u(addr)); + Literal(inst->externalInterface->load32u(addr)); return Literal(lanes); } else { - instance.externalInterface->store32(addr, - lanes[curr->index].geti32()); + inst->externalInterface->store32(addr, lanes[curr->index].geti32()); return {}; } } @@ -2870,11 +2923,10 @@ private: std::array<Literal, 2> lanes = vec.getLanesI64x2(); if (curr->isLoad()) { lanes[curr->index] = - Literal(instance.externalInterface->load64u(addr)); + Literal(inst->externalInterface->load64u(addr)); return Literal(lanes); } else { - instance.externalInterface->store64(addr, - lanes[curr->index].geti64()); + inst->externalInterface->store64(addr, lanes[curr->index].geti64()); return {}; } } @@ -2883,38 +2935,39 @@ private: } Flow visitMemorySize(MemorySize* curr) { NOTE_ENTER("MemorySize"); - return Literal::makeFromInt64(instance.memorySize, - instance.wasm.memory.indexType); + auto* inst = getMemoryInstance(); + return Literal::makeFromInt64(inst->memorySize, + inst->wasm.memory.indexType); } Flow visitMemoryGrow(MemoryGrow* curr) { NOTE_ENTER("MemoryGrow"); - auto indexType = instance.wasm.memory.indexType; + auto* inst = getMemoryInstance(); + auto indexType = inst->wasm.memory.indexType; auto fail = Literal::makeFromInt64(-1, indexType); Flow flow = this->visit(curr->delta); if (flow.breaking()) { return flow; } - Flow ret = Literal::makeFromInt64(instance.memorySize, indexType); + Flow ret = Literal::makeFromInt64(inst->memorySize, indexType); uint64_t delta = flow.getSingleValue().getUnsigned(); if (delta > uint32_t(-1) / Memory::kPageSize && indexType == Type::i32) { return fail; } - if (instance.memorySize >= uint32_t(-1) - delta && - indexType == Type::i32) { + if (inst->memorySize >= uint32_t(-1) - delta && indexType == Type::i32) { return fail; } - auto newSize = instance.memorySize + delta; - if (newSize > instance.wasm.memory.max) { + auto newSize = inst->memorySize + delta; + if (newSize > inst->wasm.memory.max) { return fail; } - if (!instance.externalInterface->growMemory( - instance.memorySize * Memory::kPageSize, - newSize * Memory::kPageSize)) { + if (!inst->externalInterface->growMemory(inst->memorySize * + Memory::kPageSize, + newSize * Memory::kPageSize)) { // We failed to grow the memory in practice, even though it was valid // to try to do so. return fail; } - instance.memorySize = newSize; + inst->memorySize = newSize; return ret; } Flow visitMemoryInit(MemoryInit* curr) { @@ -2949,13 +3002,14 @@ private: if ((uint64_t)offsetVal + sizeVal > segment.data.size()) { trap("out of bounds segment access in memory.init"); } - if (destVal + sizeVal > instance.memorySize * Memory::kPageSize) { + auto* inst = getMemoryInstance(); + if (destVal + sizeVal > inst->memorySize * Memory::kPageSize) { trap("out of bounds memory access in memory.init"); } for (size_t i = 0; i < sizeVal; ++i) { Literal addr(destVal + i); - instance.externalInterface->store8( - instance.getFinalAddressWithoutOffset(addr, 1), + inst->externalInterface->store8( + inst->getFinalAddressWithoutOffset(addr, 1), segment.data[offsetVal + i]); } return {}; @@ -2986,8 +3040,9 @@ private: Address sourceVal(source.getSingleValue().getUnsigned()); Address sizeVal(size.getSingleValue().getUnsigned()); - if (sourceVal + sizeVal > instance.memorySize * Memory::kPageSize || - destVal + sizeVal > instance.memorySize * Memory::kPageSize || + auto* inst = getMemoryInstance(); + if (sourceVal + sizeVal > inst->memorySize * Memory::kPageSize || + destVal + sizeVal > inst->memorySize * Memory::kPageSize || // FIXME: better/cheaper way to detect wrapping? sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal || destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) { @@ -3004,10 +3059,10 @@ private: step = -1; } for (int64_t i = start; i != end; i += step) { - instance.externalInterface->store8( - instance.getFinalAddressWithoutOffset(Literal(destVal + i), 1), - instance.externalInterface->load8s( - instance.getFinalAddressWithoutOffset(Literal(sourceVal + i), 1))); + inst->externalInterface->store8( + inst->getFinalAddressWithoutOffset(Literal(destVal + i), 1), + inst->externalInterface->load8s( + inst->getFinalAddressWithoutOffset(Literal(sourceVal + i), 1))); } return {}; } @@ -3031,16 +3086,17 @@ private: Address destVal(dest.getSingleValue().getUnsigned()); Address sizeVal(size.getSingleValue().getUnsigned()); + auto* inst = getMemoryInstance(); // FIXME: cheaper wrapping detection? - if (destVal > instance.memorySize * Memory::kPageSize || - sizeVal > instance.memorySize * Memory::kPageSize || - destVal + sizeVal > instance.memorySize * Memory::kPageSize) { + if (destVal > inst->memorySize * Memory::kPageSize || + sizeVal > inst->memorySize * Memory::kPageSize || + destVal + sizeVal > inst->memorySize * Memory::kPageSize) { trap("out of bounds memory access in memory.fill"); } uint8_t val(value.getSingleValue().geti32()); for (size_t i = 0; i < sizeVal; ++i) { - instance.externalInterface->store8( - instance.getFinalAddressWithoutOffset(Literal(destVal + i), 1), val); + inst->externalInterface->store8( + inst->getFinalAddressWithoutOffset(Literal(destVal + i), 1), val); } return {}; } @@ -3289,6 +3345,7 @@ protected: } ExternalInterface* externalInterface; + std::map<Name, std::shared_ptr<SubType>> linkedInstances; }; // The default ModuleInstance uses a trivial global manager @@ -3296,8 +3353,11 @@ using TrivialGlobalManager = std::map<Name, Literals>; class ModuleInstance : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> { public: - ModuleInstance(Module& wasm, ExternalInterface* externalInterface) - : ModuleInstanceBase(wasm, externalInterface) {} + ModuleInstance( + Module& wasm, + ExternalInterface* externalInterface, + std::map<Name, std::shared_ptr<ModuleInstance>> linkedInstances = {}) + : ModuleInstanceBase(wasm, externalInterface, linkedInstances) {} }; } // namespace wasm |