aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples/php-on-wasm/php-wasm.php12
-rw-r--r--examples/rubyvm-on-php-on-wasm/php-wasm.php12
-rw-r--r--src/WebAssembly/Execution/ExporterInterface.php13
-rw-r--r--src/WebAssembly/Execution/LinkErrorException.php11
-rw-r--r--src/WebAssembly/Execution/Linker.php49
-rw-r--r--src/WebAssembly/Execution/Runtime.php28
-rw-r--r--tests/src/SpecTestsuites/SpecTestsuiteBase.php136
7 files changed, 147 insertions, 114 deletions
diff --git a/examples/php-on-wasm/php-wasm.php b/examples/php-on-wasm/php-wasm.php
index fe1d327..11bb5ac 100644
--- a/examples/php-on-wasm/php-wasm.php
+++ b/examples/php-on-wasm/php-wasm.php
@@ -9,6 +9,7 @@ use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Decoder;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Extern;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Externs;
use Nsfisis\Waddiwasi\WebAssembly\Execution\FuncInst;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Linker;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Refs;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Runtime;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Store;
@@ -123,7 +124,16 @@ $imports = [
],
];
-$runtime = Runtime::instantiate(Store::empty(), $module, $imports);
+$store = Store::empty();
+$linker = new Linker($store);
+
+foreach ($imports as $moduleName => $moduleImports) {
+ foreach ($moduleImports as $importName => $import) {
+ $linker->register($moduleName, $importName, $import);
+ }
+}
+
+$runtime = Runtime::instantiate($store, $module, $linker->resolve($module));
$codePtr = allocateStringOnWasmMemory($runtime, PHP_HELLO_WORLD);
$results = $runtime->invoke("php_wasm_run", [$codePtr]);
diff --git a/examples/rubyvm-on-php-on-wasm/php-wasm.php b/examples/rubyvm-on-php-on-wasm/php-wasm.php
index 726f6d1..b86c6a2 100644
--- a/examples/rubyvm-on-php-on-wasm/php-wasm.php
+++ b/examples/rubyvm-on-php-on-wasm/php-wasm.php
@@ -9,6 +9,7 @@ use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Decoder;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Extern;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Externs;
use Nsfisis\Waddiwasi\WebAssembly\Execution\FuncInst;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Linker;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Refs;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Runtime;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Store;
@@ -123,7 +124,16 @@ $imports = [
],
];
-$runtime = Runtime::instantiate(Store::empty(), $module, $imports);
+$store = Store::empty();
+$linker = new Linker($store);
+
+foreach ($imports as $moduleName => $moduleImports) {
+ foreach ($moduleImports as $importName => $import) {
+ $linker->register($moduleName, $importName, $import);
+ }
+}
+
+$runtime = Runtime::instantiate($store, $module, $linker->resolve($module));
$codePtr = allocateStringOnWasmMemory($runtime, strtr(PHP_HELLO_WORLD, ['%DIR%' => __DIR__]));
$results = $runtime->invoke("php_wasm_run", [$codePtr]);
diff --git a/src/WebAssembly/Execution/ExporterInterface.php b/src/WebAssembly/Execution/ExporterInterface.php
new file mode 100644
index 0000000..9c2d965
--- /dev/null
+++ b/src/WebAssembly/Execution/ExporterInterface.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Nsfisis\Waddiwasi\WebAssembly\Execution;
+
+interface ExporterInterface
+{
+ /**
+ * @return list<ExportInst>
+ */
+ public function exports(): array;
+}
diff --git a/src/WebAssembly/Execution/LinkErrorException.php b/src/WebAssembly/Execution/LinkErrorException.php
new file mode 100644
index 0000000..35db57f
--- /dev/null
+++ b/src/WebAssembly/Execution/LinkErrorException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Nsfisis\Waddiwasi\WebAssembly\Execution;
+
+use RuntimeException;
+
+final class LinkErrorException extends RuntimeException
+{
+}
diff --git a/src/WebAssembly/Execution/Linker.php b/src/WebAssembly/Execution/Linker.php
new file mode 100644
index 0000000..3c9c1d0
--- /dev/null
+++ b/src/WebAssembly/Execution/Linker.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Nsfisis\Waddiwasi\WebAssembly\Execution;
+
+use Nsfisis\Waddiwasi\WebAssembly\Structure\Modules\Module;
+
+final class Linker
+{
+ /**
+ * @var array<string, array<string, ExternVal>>
+ */
+ private array $symbols = [];
+
+ public function __construct(
+ private Store $store,
+ ) {
+ }
+
+ public function register(string $namespace, string $name, Extern $extern): void
+ {
+ $externVal = $this->store->register($extern);
+ $this->symbols[$namespace][$name] = $externVal;
+ }
+
+ public function registerNamespace(string $namespace, ExporterInterface $exporter): void
+ {
+ foreach ($exporter->exports() as $export) {
+ $this->symbols[$namespace][$export->name] = $export->value;
+ }
+ }
+
+ /**
+ * @return list<ExternVal>
+ */
+ public function resolve(Module $module): array
+ {
+ $externVals = [];
+ foreach ($module->imports as $import) {
+ $externVal = $this->symbols[$import->module][$import->name] ?? null;
+ if ($externVal === null) {
+ throw new LinkErrorException("import not found: {$import->module}::{$import->name}");
+ }
+ $externVals[] = $externVal;
+ }
+ return $externVals;
+ }
+}
diff --git a/src/WebAssembly/Execution/Runtime.php b/src/WebAssembly/Execution/Runtime.php
index 07dc0d0..c4a78c8 100644
--- a/src/WebAssembly/Execution/Runtime.php
+++ b/src/WebAssembly/Execution/Runtime.php
@@ -39,7 +39,7 @@ use function sqrt;
use function unpack;
use const PHP_INT_MIN;
-final class Runtime
+final class Runtime implements ExporterInterface
{
/**
* @var array<string, array{int, int}>
@@ -54,28 +54,9 @@ final class Runtime
}
/**
- * @param array<string, array<string, Extern>> $imports
- */
- public static function instantiate(
- Store $store,
- Module $module,
- array $imports,
- ): self {
- $externVals = [];
- foreach ($module->imports as $import) {
- $extern = $imports[$import->module][$import->name] ?? null;
- if ($extern === null) {
- throw new RuntimeException("instantiate: import not found: {$import->module}::{$import->name}");
- }
- $externVals[] = $store->register($extern);
- }
- return self::doInstantiate($store, $module, $externVals);
- }
-
- /**
* @param list<ExternVal> $externVals
*/
- private static function doInstantiate(
+ public static function instantiate(
Store $store,
Module $module,
array $externVals,
@@ -159,6 +140,11 @@ final class Runtime
return new self($store, $stack, $moduleInst);
}
+ public function exports(): array
+ {
+ return $this->module->exports;
+ }
+
public function getExport(string $name): ?ExternVal
{
foreach ($this->module->exports as $export) {
diff --git a/tests/src/SpecTestsuites/SpecTestsuiteBase.php b/tests/src/SpecTestsuites/SpecTestsuiteBase.php
index f5a9f86..9b7f24e 100644
--- a/tests/src/SpecTestsuites/SpecTestsuiteBase.php
+++ b/tests/src/SpecTestsuites/SpecTestsuiteBase.php
@@ -8,9 +8,9 @@ use Nsfisis\Waddiwasi\Stream\FileStream;
use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Decoder;
use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\InvalidBinaryFormatException;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Extern;
-use Nsfisis\Waddiwasi\WebAssembly\Execution\ExternVals;
use Nsfisis\Waddiwasi\WebAssembly\Execution\FuncInst;
use Nsfisis\Waddiwasi\WebAssembly\Execution\GlobalInst;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Linker;
use Nsfisis\Waddiwasi\WebAssembly\Execution\MemInst;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Ref;
use Nsfisis\Waddiwasi\WebAssembly\Execution\Refs\RefExtern;
@@ -52,57 +52,43 @@ abstract class SpecTestsuiteBase extends TestCase
$wasmBinaryStream = new FileStream($filePath);
$module = (new Decoder($wasmBinaryStream))->decode();
self::$modules[$moduleName] = $module;
- $importObj = [
- 'spectest' => [
- 'memory' => Extern::Mem(new MemInst(new MemType(new Limits(1, 2)))),
- 'table' => Extern::Table(new TableInst(new TableType(new Limits(10, 20), ValType::FuncRef), [
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- Ref::RefNull(ValType::FuncRef),
- ])),
- 'global_i32' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::I32), 666)),
- 'global_i64' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::I64), 666)),
- 'global_f32' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::F32), 666.6)),
- 'global_f64' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::F64), 666.6)),
- 'print' => Extern::Func(FuncInst::Host(new FuncType([], []), fn () => null)),
- 'print_i32' => Extern::Func(FuncInst::Host(new FuncType([ValType::I32], []), fn () => null)),
- 'print_i64' => Extern::Func(FuncInst::Host(new FuncType([ValType::I64], []), fn () => null)),
- 'print_f32' => Extern::Func(FuncInst::Host(new FuncType([ValType::F32], []), fn () => null)),
- 'print_f64' => Extern::Func(FuncInst::Host(new FuncType([ValType::F64], []), fn () => null)),
- 'print_i32_f32' => Extern::Func(FuncInst::Host(new FuncType([ValType::I32, ValType::F32], []), fn () => null)),
- 'print_f64_f64' => Extern::Func(FuncInst::Host(new FuncType([ValType::F64, ValType::F64], []), fn () => null)),
- ],
- ];
- foreach (self::$registeredModules as $registeredModuleName => $registeredModule) {
- $registeredRuntime = self::$registeredRuntimes[$registeredModuleName];
- foreach ($registeredModule->exports as $export) {
- $externVal = $registeredRuntime->getExport($export->name);
- if ($externVal instanceof ExternVals\Func) {
- $fn = $registeredRuntime->store->funcs[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Func($fn);
- } elseif ($externVal instanceof ExternVals\Table) {
- $tab = $registeredRuntime->store->tables[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Table($tab);
- } elseif ($externVal instanceof ExternVals\Mem) {
- $mem = $registeredRuntime->store->mems[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Mem($mem);
- } elseif ($externVal instanceof ExternVals\Global_) {
- $gl = $registeredRuntime->store->globals[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Global_($gl);
- }
- }
- }
if (self::$store === null) {
self::$store = Store::empty();
}
- $runtime = Runtime::instantiate(self::$store, $module, $importObj);
+ $spectestExterns = [
+ 'memory' => Extern::Mem(new MemInst(new MemType(new Limits(1, 2)))),
+ 'table' => Extern::Table(new TableInst(new TableType(new Limits(10, 20), ValType::FuncRef), [
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ Ref::RefNull(ValType::FuncRef),
+ ])),
+ 'global_i32' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::I32), 666)),
+ 'global_i64' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::I64), 666)),
+ 'global_f32' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::F32), 666.6)),
+ 'global_f64' => Extern::Global_(new GlobalInst(new GlobalType(Mut::Const, ValType::F64), 666.6)),
+ 'print' => Extern::Func(FuncInst::Host(new FuncType([], []), fn () => null)),
+ 'print_i32' => Extern::Func(FuncInst::Host(new FuncType([ValType::I32], []), fn () => null)),
+ 'print_i64' => Extern::Func(FuncInst::Host(new FuncType([ValType::I64], []), fn () => null)),
+ 'print_f32' => Extern::Func(FuncInst::Host(new FuncType([ValType::F32], []), fn () => null)),
+ 'print_f64' => Extern::Func(FuncInst::Host(new FuncType([ValType::F64], []), fn () => null)),
+ 'print_i32_f32' => Extern::Func(FuncInst::Host(new FuncType([ValType::I32, ValType::F32], []), fn () => null)),
+ 'print_f64_f64' => Extern::Func(FuncInst::Host(new FuncType([ValType::F64, ValType::F64], []), fn () => null)),
+ ];
+ $linker = new Linker(self::$store);
+ foreach ($spectestExterns as $externName => $extern) {
+ $linker->register('spectest', $externName, $extern);
+ }
+ foreach (self::$registeredRuntimes as $registeredModuleName => $registeredRuntime) {
+ $linker->registerNamespace($registeredModuleName, $registeredRuntime);
+ }
+ $runtime = Runtime::instantiate(self::$store, $module, $linker->resolve($module));
self::$runtimes[$moduleName] = $runtime;
if ($moduleName !== '_') {
self::$modules['_'] = $module;
@@ -192,31 +178,15 @@ abstract class SpecTestsuiteBase extends TestCase
$wasmBinaryStream = new FileStream($filePath);
$module = (new Decoder($wasmBinaryStream))->decode();
$exception = null;
- $importObj = [];
- foreach (self::$registeredModules as $registeredModuleName => $registeredModule) {
- $registeredRuntime = self::$registeredRuntimes[$registeredModuleName];
- foreach ($registeredModule->exports as $export) {
- $externVal = $registeredRuntime->getExport($export->name);
- if ($externVal instanceof ExternVals\Func) {
- $fn = $registeredRuntime->store->funcs[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Func($fn);
- } elseif ($externVal instanceof ExternVals\Table) {
- $tab = $registeredRuntime->store->tables[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Table($tab);
- } elseif ($externVal instanceof ExternVals\Mem) {
- $mem = $registeredRuntime->store->mems[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Mem($mem);
- } elseif ($externVal instanceof ExternVals\Global_) {
- $gl = $registeredRuntime->store->globals[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Global_($gl);
- }
- }
- }
if (self::$store === null) {
self::$store = Store::empty();
}
+ $linker = new Linker(self::$store);
+ foreach (self::$registeredRuntimes as $registeredModuleName => $registeredRuntime) {
+ $linker->registerNamespace($registeredModuleName, $registeredRuntime);
+ }
try {
- Runtime::instantiate(self::$store, $module, $importObj);
+ Runtime::instantiate(self::$store, $module, $linker->resolve($module));
} catch (RuntimeException $e) {
$exception = $e;
}
@@ -233,31 +203,15 @@ abstract class SpecTestsuiteBase extends TestCase
$wasmBinaryStream = new FileStream($filePath);
$module = (new Decoder($wasmBinaryStream))->decode();
$exception = null;
- $importObj = [];
- foreach (self::$registeredModules as $registeredModuleName => $registeredModule) {
- $registeredRuntime = self::$registeredRuntimes[$registeredModuleName];
- foreach ($registeredModule->exports as $export) {
- $externVal = $registeredRuntime->getExport($export->name);
- if ($externVal instanceof ExternVals\Func) {
- $fn = $registeredRuntime->store->funcs[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Func($fn);
- } elseif ($externVal instanceof ExternVals\Table) {
- $tab = $registeredRuntime->store->tables[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Table($tab);
- } elseif ($externVal instanceof ExternVals\Mem) {
- $mem = $registeredRuntime->store->mems[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Mem($mem);
- } elseif ($externVal instanceof ExternVals\Global_) {
- $gl = $registeredRuntime->store->globals[$registeredRuntime->getExport($export->name)->addr];
- $importObj[$registeredModuleName][$export->name] = Extern::Global_($gl);
- }
- }
- }
if (self::$store === null) {
self::$store = Store::empty();
}
+ $linker = new Linker(self::$store);
+ foreach (self::$registeredRuntimes as $registeredModuleName => $registeredRuntime) {
+ $linker->registerNamespace($registeredModuleName, $registeredRuntime);
+ }
try {
- Runtime::instantiate(self::$store, $module, $importObj);
+ Runtime::instantiate(self::$store, $module, $linker->resolve($module));
} catch (RuntimeException $e) {
$exception = $e;
}