diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-07-12 22:39:20 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-07-13 08:23:06 +0900 |
| commit | e94a046a548795b8675bc109c87413de6bca53e7 (patch) | |
| tree | 9958efead32039de87f3564c77a7b09f978a13ef | |
| parent | d1c268b76f65e69ea708096d5023c4d731cff594 (diff) | |
| download | php-waddiwasi-e94a046a548795b8675bc109c87413de6bca53e7.tar.gz php-waddiwasi-e94a046a548795b8675bc109c87413de6bca53e7.tar.zst php-waddiwasi-e94a046a548795b8675bc109c87413de6bca53e7.zip | |
feat: add Linker class
| -rw-r--r-- | examples/php-on-wasm/php-wasm.php | 12 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/php-wasm.php | 12 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/ExporterInterface.php | 13 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/LinkErrorException.php | 11 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/Linker.php | 49 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/Runtime.php | 28 | ||||
| -rw-r--r-- | tests/src/SpecTestsuites/SpecTestsuiteBase.php | 136 |
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; } |
