diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-01-27 13:22:56 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-02-26 11:07:06 +0900 |
| commit | 900377463a8264871ee42e488112b076b7973b6a (patch) | |
| tree | bf727d3484ca7c8d35f18ef29ea8d9305d4b57da /src/Execution/Allocator.php | |
| parent | e2495878b872b341e6e04eed31dd255b1a6e256f (diff) | |
| download | php-waddiwasi-900377463a8264871ee42e488112b076b7973b6a.tar.gz php-waddiwasi-900377463a8264871ee42e488112b076b7973b6a.tar.zst php-waddiwasi-900377463a8264871ee42e488112b076b7973b6a.zip | |
feat: partially implement execution
Diffstat (limited to 'src/Execution/Allocator.php')
| -rw-r--r-- | src/Execution/Allocator.php | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/Execution/Allocator.php b/src/Execution/Allocator.php new file mode 100644 index 0000000..ad62fc7 --- /dev/null +++ b/src/Execution/Allocator.php @@ -0,0 +1,162 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\Execution; + +use Nsfisis\Waddiwasi\Structure\Modules\ExportDescs; +use Nsfisis\Waddiwasi\Structure\Modules\Func; +use Nsfisis\Waddiwasi\Structure\Modules\Module; +use Nsfisis\Waddiwasi\Structure\Types\GlobalType; +use Nsfisis\Waddiwasi\Structure\Types\MemType; +use Nsfisis\Waddiwasi\Structure\Types\RefType; +use Nsfisis\Waddiwasi\Structure\Types\TableType; + +final readonly class Allocator +{ + public function __construct( + private readonly Store $store, + ) { + } + + /** + * @param list<ExternVal> $externVals + */ + public function allocPreInitModule( + Module $module, + array $externVals, + ): ModuleInst { + $m = new ModuleInst($module->types, [], [], [], [], [], [], []); + + foreach ($externVals as $externVal) { + if ($externVal instanceof ExternVals\Global_) { + $m->globalAddrs[] = $externVal->addr; + } + } + foreach ($module->funcs as $func) { + $m->funcAddrs[] = $this->allocFunc($func, $m); + } + + return $m; + } + + /** + * @param list<ExternVal> $externVals + * @param list<Val> $vals + * @param list<list<Ref>> $refsList + * @param list<FuncAddr> $preAllocatedFuncs + */ + public function allocModule( + Module $module, + array $externVals, + array $vals, + array $refsList, + array $preAllocatedFuncs, + ): ModuleInst { + $m = new ModuleInst($module->types, [], [], [], [], [], [], []); + + foreach ($externVals as $externVal) { + match ($externVal::class) { + ExternVals\Func::class => $m->funcAddrs[] = $externVal->addr, + ExternVals\Table::class => $m->tableAddrs[] = $externVal->addr, + ExternVals\Mem::class => $m->memAddrs[] = $externVal->addr, + ExternVals\Global_::class => $m->globalAddrs[] = $externVal->addr, + default => throw new \RuntimeException("unreachable"), + }; + } + + foreach ($preAllocatedFuncs as $funcAddr) { + $m->funcAddrs[] = $funcAddr; + $funcInst = $this->store->funcs[$funcAddr->value]; + assert($funcInst instanceof FuncInsts\Wasm); + // @phpstan-ignore-next-line + $this->store->funcs[$funcAddr->value] = FuncInst::Wasm( + $funcInst->type, + $m, + $funcInst->code, + ); + } + foreach ($module->tables as $table) { + $m->tableAddrs[] = $this->allocTable($table->type, Ref::RefNull($table->type->refType)); + } + foreach ($module->mems as $mem) { + $m->memAddrs[] = $this->allocMem($mem->type); + } + foreach ($module->datas as $data) { + $m->dataAddrs[] = $this->allocData($data->init); + } + + foreach ($module->globals as $i => $global) { + $m->globalAddrs[] = $this->allocGlobal($global->type, $vals[$i]); + } + foreach ($module->elems as $i => $elem) { + $m->elemAddrs[] = $this->allocElem($elem->type, $refsList[$i]); + } + + foreach ($module->exports as $export) { + $value = match ($export->desc::class) { + ExportDescs\Func::class => ExternVal::Func($m->funcAddrs[$export->desc->func->value]), + ExportDescs\Table::class => ExternVal::Table($m->tableAddrs[$export->desc->table->value]), + ExportDescs\Mem::class => ExternVal::Mem($m->memAddrs[$export->desc->mem->value]), + ExportDescs\Global_::class => ExternVal::Global_($m->globalAddrs[$export->desc->global->value]), + default => throw new \RuntimeException("unreachable"), + }; + $m->exports[] = new ExportInst($export->name, $value); + } + + return $m; + } + + private function allocFunc(Func $func, ModuleInst $moduleInst): FuncAddr + { + $funcType = $moduleInst->types[$func->type->value]; + $funcInst = FuncInst::Wasm($funcType, $moduleInst, $func); + $this->store->funcs[] = $funcInst; + return new FuncAddr(count($this->store->funcs) - 1); + } + + private function allocTable(TableType $tableType, Ref $ref): TableAddr + { + $minSize = $tableType->limits->min; + $elem = array_fill(0, $minSize, $ref); + $tableInst = new TableInst($tableType, $elem); + $this->store->tables[] = $tableInst; + return new TableAddr(count($this->store->tables) - 1); + } + + private function allocMem(MemType $memType): MemAddr + { + $minSize = $memType->limits->min; + $data = array_fill(0, $minSize * 64 * 1024, 0); + $memInst = new MemInst($memType, $data); + $this->store->mems[] = $memInst; + return new MemAddr(count($this->store->mems) - 1); + } + + private function allocGlobal(GlobalType $globalType, Val $val): GlobalAddr + { + $globalInst = new GlobalInst($globalType, $val); + $this->store->globals[] = $globalInst; + return new GlobalAddr(count($this->store->globals) - 1); + } + + /** + * @param list<Ref> $elem + */ + private function allocElem(RefType $refType, array $elem): ElemAddr + { + $elemInst = new ElemInst($refType, $elem); + $this->store->elems[] = $elemInst; + return new ElemAddr(count($this->store->elems) - 1); + } + + /** + * @param list<Byte> $data + */ + private function allocData(array $data): DataAddr + { + $dataInst = new DataInst($data); + $this->store->datas[] = $dataInst; + return new DataAddr(count($this->store->datas) - 1); + } +} |
