aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Execution/MemInst.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/Execution/MemInst.php')
-rw-r--r--src/Execution/MemInst.php93
1 files changed, 82 insertions, 11 deletions
diff --git a/src/Execution/MemInst.php b/src/Execution/MemInst.php
index 21dd353..370a980 100644
--- a/src/Execution/MemInst.php
+++ b/src/Execution/MemInst.php
@@ -6,6 +6,7 @@ namespace Nsfisis\Waddiwasi\Execution;
use FFI;
use FFI\CData;
+use Nsfisis\Waddiwasi\Structure\Types\Limits;
use Nsfisis\Waddiwasi\Structure\Types\MemType;
use function assert;
use function count;
@@ -14,6 +15,8 @@ final class MemInst
{
private const PAGE_SIZE = 64 * 1024;
+ private const MAX_PAGES = 0x10000;
+
private CData $dataU8;
private CData $dataS8;
@@ -54,19 +57,63 @@ final class MemInst
private CData $dataF64_6;
private CData $dataF64_7;
- private readonly int $dataSize;
+ private int $dataSize;
private readonly FFI $ffi;
public function __construct(
- public readonly MemType $type,
+ public MemType $type,
) {
$this->ffi = FFI::cdef();
+ $this->initInternalMemory($type->limits->min);
+ }
- $minSize = $type->limits->min;
- // @todo hack
- $minSize *= 8;
- $this->dataSize = $minSize * self::PAGE_SIZE;
+ public function size(): int
+ {
+ return $this->dataSize;
+ }
+
+ public function nPages(): int
+ {
+ return $this->size() / self::PAGE_SIZE;
+ }
+
+ /**
+ * @return int
+ * Returns the original size of the memory in pages or -1 if failed.
+ */
+ public function grow(int $n): int
+ {
+ $sz = $this->nPages();
+ $len = $sz + $n;
+ if (self::MAX_PAGES < $len) {
+ return -1;
+ }
+
+ $limits = $this->type->limits;
+ $limits_ = new Limits($len, $limits->max);
+ if (!$limits_->isValid()) {
+ return -1;
+ }
+
+ $originalSize = $this->size();
+ // @phpstan-ignore-next-line
+ $originalData = $this->ffi->new("uint8_t[$originalSize]");
+ assert($originalData !== null);
+
+ $this->initInternalMemory($len);
+
+ for ($i = 0; $i < $originalSize; $i++) {
+ // @phpstan-ignore-next-line
+ $this->dataU8[$i] = $originalData[$i];
+ }
+
+ return $sz;
+ }
+
+ private function initInternalMemory(int $n): void
+ {
+ $this->dataSize = $n * self::PAGE_SIZE;
// @phpstan-ignore-next-line
$this->dataU8 = $this->ffi->new("uint8_t[$this->dataSize+8]");
@@ -160,11 +207,6 @@ final class MemInst
FFI::memset($this->dataU8, 0, $this->dataSize);
}
- public function size(): int
- {
- return $this->dataSize;
- }
-
/**
* @param list<int> $data
*/
@@ -180,6 +222,35 @@ final class MemInst
}
}
+ public function memcpy(int $dst, int $src, int $len): void
+ {
+ assert(0 <= $len);
+ assert(0 <= $src);
+ assert(0 <= $dst);
+ assert($src + $len <= $this->size());
+ assert($dst + $len <= $this->size());
+ if ($src === $dst || $len === 0) {
+ return;
+ }
+ for ($i = 0; $i < $len; $i++) {
+ $s = ($dst < $src) ? ($src + $i) : ($src + $len - 1 - $i);
+ $d = ($dst < $src) ? ($dst + $i) : ($dst + $len - 1 - $i);
+ $x = $this->loadByte($s);
+ assert($x !== null);
+ $this->storeByte($d, $x);
+ }
+ }
+
+ public function memset(int $dst, int $c, int $len): void
+ {
+ assert(0 <= $len);
+ assert(0 <= $dst);
+ assert($dst + $len <= $this->size());
+ for ($i = 0; $i < $len; $i++) {
+ $this->storeI32_s8($dst + $i, $c);
+ }
+ }
+
/**
* @return ?S32
*/