diff options
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/.gitignore | 1 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/HelloWorld.php | 20 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/HelloWorld.rb | 1 | ||||
| -rwxr-xr-x | examples/rubyvm-on-php-on-wasm/HelloWorld.sh | 1 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/HelloWorld.yarv | bin | 0 -> 221 bytes | |||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/composer.json | 20 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/composer.lock | 920 | ||||
| -rw-r--r-- | examples/rubyvm-on-php-on-wasm/php-wasm.php | 1615 | ||||
| -rwxr-xr-x | examples/rubyvm-on-php-on-wasm/php-wasm.wasm | bin | 0 -> 4863136 bytes |
9 files changed, 2578 insertions, 0 deletions
diff --git a/examples/rubyvm-on-php-on-wasm/.gitignore b/examples/rubyvm-on-php-on-wasm/.gitignore new file mode 100644 index 0000000..61ead86 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/examples/rubyvm-on-php-on-wasm/HelloWorld.php b/examples/rubyvm-on-php-on-wasm/HelloWorld.php new file mode 100644 index 0000000..7c37ac2 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/HelloWorld.php @@ -0,0 +1,20 @@ +<?php + +require_once __DIR__ . '/vendor/autoload.php'; + +define('STDIN', fopen('php://stdin', 'r')); +define('STDOUT', fopen('php://stdout', 'r')); +define('STDERR', fopen('php://stderr', 'r')); + +$rubyVM = new \RubyVM\VM\Core\Runtime\RubyVM( + new \RubyVM\VM\Core\Runtime\Option( + reader: new \RubyVM\VM\Stream\BinaryStreamReader( + streamHandler: new \RubyVM\VM\Stream\FileStreamHandler( + __DIR__ . '/HelloWorld.yarv', + ), + ), + logger: new \Psr\Log\NullLogger(), + ), +); +$executor = $rubyVM->disassemble(); +$executor->execute(); diff --git a/examples/rubyvm-on-php-on-wasm/HelloWorld.rb b/examples/rubyvm-on-php-on-wasm/HelloWorld.rb new file mode 100644 index 0000000..f94759e --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/HelloWorld.rb @@ -0,0 +1 @@ +puts RubyVM::InstructionSequence.compile("puts 'HelloWorld!\n'", "HelloWorld.rb").to_binary diff --git a/examples/rubyvm-on-php-on-wasm/HelloWorld.sh b/examples/rubyvm-on-php-on-wasm/HelloWorld.sh new file mode 100755 index 0000000..c5fc8ae --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/HelloWorld.sh @@ -0,0 +1 @@ +php -d memory_limit=-1 -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G ./php-wasm.php diff --git a/examples/rubyvm-on-php-on-wasm/HelloWorld.yarv b/examples/rubyvm-on-php-on-wasm/HelloWorld.yarv Binary files differnew file mode 100644 index 0000000..4a4cb1c --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/HelloWorld.yarv diff --git a/examples/rubyvm-on-php-on-wasm/composer.json b/examples/rubyvm-on-php-on-wasm/composer.json new file mode 100644 index 0000000..0e4a7b8 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/composer.json @@ -0,0 +1,20 @@ +{ + "name": "nsfisis/waddiwasi-example", + "type": "project", + "description": "Waddiwasi example", + "license": "MIT", + "authors": [ + { + "name": "nsfisis" + } + ], + "autoload": { + "psr-4": { + "Nsfisis\\Waddiwasi\\": "../../src/", + "Nsfisis\\Waddiwasi\\Examples\\": "src/" + } + }, + "require": { + "m3m0r7/rubyvm-on-php": "^0.3.3" + } +} diff --git a/examples/rubyvm-on-php-on-wasm/composer.lock b/examples/rubyvm-on-php-on-wasm/composer.lock new file mode 100644 index 0000000..8bbbef2 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/composer.lock @@ -0,0 +1,920 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "b1aa666a62b5f0727e6936ef6bf2cd70", + "packages": [ + { + "name": "m3m0r7/rubyvm-on-php", + "version": "0.3.3.0", + "source": { + "type": "git", + "url": "https://github.com/m3m0r7/rubyvm-on-php.git", + "reference": "a568cabf4b71e7f8a3efebcaa3b77ea2c8bc2f5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/m3m0r7/rubyvm-on-php/zipball/a568cabf4b71e7f8a3efebcaa3b77ea2c8bc2f5c", + "reference": "a568cabf4b71e7f8a3efebcaa3b77ea2c8bc2f5c", + "shasum": "" + }, + "require": { + "monolog/monolog": "^3.4", + "php": ">=8.2", + "symfony/console": "^6.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.21", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.2", + "rector/rector": "^0.18.3", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "RubyVM\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "m3m0r7", + "homepage": "https://i.mem.ooo" + } + ], + "support": { + "issues": "https://github.com/m3m0r7/rubyvm-on-php/issues", + "source": "https://github.com/m3m0r7/rubyvm-on-php/tree/0.3.3.0" + }, + "time": "2023-12-28T04:25:48+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.7.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8", + "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^10.5.17", + "predis/predis": "^1.1 || ^2", + "ruflin/elastica": "^7", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.7.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-06-28T09:40:51+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "symfony/console", + "version": "v6.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9", + "reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T09:49:33+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/string", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8", + "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T09:27:18+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/examples/rubyvm-on-php-on-wasm/php-wasm.php b/examples/rubyvm-on-php-on-wasm/php-wasm.php new file mode 100644 index 0000000..398d377 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/php-wasm.php @@ -0,0 +1,1615 @@ +<?php + +declare(strict_types=1); + +require_once __DIR__ . '/vendor/autoload.php'; + +use Nsfisis\Waddiwasi\BinaryFormat\Decoder; +use Nsfisis\Waddiwasi\BinaryFormat\InvalidBinaryFormatException; +use Nsfisis\Waddiwasi\Execution\ExternVal; +use Nsfisis\Waddiwasi\Execution\FuncInst; +use Nsfisis\Waddiwasi\Execution\MemInst; +use Nsfisis\Waddiwasi\Execution\Refs; +use Nsfisis\Waddiwasi\Execution\Runtime; +use Nsfisis\Waddiwasi\Execution\Store; +use Nsfisis\Waddiwasi\Structure\Types\FuncType; +use Nsfisis\Waddiwasi\Structure\Types\NumType; +use Nsfisis\Waddiwasi\Structure\Types\ResultType; +use Nsfisis\Waddiwasi\Structure\Types\ValType; + +const PHP_EMPTY = ''; + +const PHP_HELLO_WORLD = <<<'EOS' +require_once __DIR__ . '/HelloWorld.php'; +EOS; + +$wasmBinary = file_get_contents(__DIR__ . '/php-wasm.wasm'); +\assert($wasmBinary !== false); + +try { + $module = (new Decoder($wasmBinary))->decode(); +} catch (InvalidBinaryFormatException $e) { + fprintf(STDERR, $e->getMessage() . "\n"); + exit(1); +} + +$hostFuncs = [ + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env__invoke_iii(...), 'env::invoke_iii'), + makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__invoke_iiiii(...), 'env::invoke_iiiii'), + makeHostFunc('(i32) -> ()', hostFunc__env__invoke_v(...), 'env::invoke_v'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env__invoke_iiii(...), 'env::invoke_iiii'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env__invoke_ii(...), 'env::invoke_ii'), + makeHostFunc('() -> ()', hostFunc__env__abort(...), 'env::abort'), + makeHostFunc('(i32) -> ()', hostFunc__env__exit(...), 'env::exit'), + makeHostFunc('(i32, i32, i32, i32) -> ()', hostFunc__env__invoke_viii(...), 'env::invoke_viii'), + makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env__invoke_vii(...), 'env::invoke_vii'), + makeHostFunc('(i32, i32) -> ()', hostFunc__env__invoke_vi(...), 'env::invoke_vi'), + makeHostFunc('(i32) -> (i32)', hostFunc__env__invoke_i(...), 'env::invoke_i'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__invoke_iiiiiii(...), 'env::invoke_iiiiiii'), + makeHostFunc('(i32, i32, i32, i32) -> ()', hostFunc__env____assert_fail(...), 'env::__assert_fail'), + makeHostFunc('(i32, i32, i32, i32, i32) -> ()', hostFunc__env__invoke_viiii(...), 'env::invoke_viiii'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> ()', hostFunc__env__invoke_viiiii(...), 'env::invoke_viiiii'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__invoke_iiiiii(...), 'env::invoke_iiiiii'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__invoke_iiiiiiiiii(...), 'env::invoke_iiiiiiiiii'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env__strftime(...), 'env::strftime'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env__getaddrinfo(...), 'env::getaddrinfo'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__gethostbyname_r(...), 'env::gethostbyname_r'), + makeHostFunc('() -> (i32)', hostFunc__env__getdtablesize(...), 'env::getdtablesize'), + makeHostFunc('(i32) -> (i32)', hostFunc__env__getprotobyname(...), 'env::getprotobyname'), + makeHostFunc('(i32) -> (i32)', hostFunc__env__getprotobynumber(...), 'env::getprotobynumber'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env__strptime(...), 'env::strptime'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__getnameinfo(...), 'env::getnameinfo'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> ()', hostFunc__env__invoke_viiiiii(...), 'env::invoke_viiiiii'), + makeHostFunc('(i32, i32, i32, f64, i32, i32) -> ()', hostFunc__env__invoke_viidii(...), 'env::invoke_viidii'), + makeHostFunc('(i32) -> (i32)', hostFunc__env__getcontext(...), 'env::getcontext'), + makeHostFunc('(i32, i32, i32, i32) -> ()', hostFunc__env__makecontext(...), 'env::makecontext'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env__swapcontext(...), 'env::swapcontext'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__environ_sizes_get(...), 'wasi_snapshot_preview1::environ_sizes_get'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__environ_get(...), 'wasi_snapshot_preview1::environ_get'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_fcntl64(...), 'env::__syscall_fcntl64'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_ioctl(...), 'env::__syscall_ioctl'), + makeHostFunc('(i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_close(...), 'wasi_snapshot_preview1::fd_close'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_read(...), 'wasi_snapshot_preview1::fd_read'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_write(...), 'wasi_snapshot_preview1::fd_write'), + makeHostFunc('(i32) -> ()', hostFunc__wasi_snapshot_preview1__proc_exit(...), 'wasi_snapshot_preview1::proc_exit'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_faccessat(...), 'env::__syscall_faccessat'), + makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_chdir(...), 'env::__syscall_chdir'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_chmod(...), 'env::__syscall_chmod'), + makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_fchownat(...), 'env::__syscall_fchownat'), + makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_dup(...), 'env::__syscall_dup'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_dup3(...), 'env::__syscall_dup3'), + makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env__emscripten_memcpy_js(...), 'env::emscripten_memcpy_js'), + makeHostFunc('() -> (f64)', hostFunc__env__emscripten_date_now(...), 'env::emscripten_date_now'), + makeHostFunc('() -> (i32)', hostFunc__env___emscripten_get_now_is_monotonic(...), 'env::_emscripten_get_now_is_monotonic'), + makeHostFunc('() -> (f64)', hostFunc__env__emscripten_get_now(...), 'env::emscripten_get_now'), + makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_fdatasync(...), 'env::__syscall_fdatasync'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_openat(...), 'env::__syscall_openat'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_fstat64(...), 'env::__syscall_fstat64'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_stat64(...), 'env::__syscall_stat64'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_newfstatat(...), 'env::__syscall_newfstatat'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_lstat64(...), 'env::__syscall_lstat64'), + makeHostFunc('(i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_sync(...), 'wasi_snapshot_preview1::fd_sync'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_getcwd(...), 'env::__syscall_getcwd'), + makeHostFunc('(i32) -> ()', hostFunc__env__emscripten_err(...), 'env::emscripten_err'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_fdstat_get(...), 'wasi_snapshot_preview1::fd_fdstat_get'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_mkdirat(...), 'env::__syscall_mkdirat'), + makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_pipe(...), 'env::__syscall_pipe'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_poll(...), 'env::__syscall_poll'), + makeHostFunc('(i32, i32) -> ()', hostFunc__env____call_sighandler(...), 'env::__call_sighandler'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_getdents64(...), 'env::__syscall_getdents64'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_readlinkat(...), 'env::__syscall_readlinkat'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_renameat(...), 'env::__syscall_renameat'), + makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_rmdir(...), 'env::__syscall_rmdir'), + makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall__newselect(...), 'env::__syscall__newselect'), + makeHostFunc('(i32, f64) -> (i32)', hostFunc__env___setitimer_js(...), 'env::_setitimer_js'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_statfs64(...), 'env::__syscall_statfs64'), + makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_symlink(...), 'env::__syscall_symlink'), + makeHostFunc('() -> (i32)', hostFunc__env__emscripten_get_heap_max(...), 'env::emscripten_get_heap_max'), + makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___tzset_js(...), 'env::_tzset_js'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_unlinkat(...), 'env::__syscall_unlinkat'), + makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_utimensat(...), 'env::__syscall_utimensat'), + makeHostFunc('(i32) -> (i32)', hostFunc__env__emscripten_resize_heap(...), 'env::emscripten_resize_heap'), + makeHostFunc('() -> ()', hostFunc__env___emscripten_throw_longjmp(...), 'env::_emscripten_throw_longjmp'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_accept4(...), 'env::__syscall_accept4'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_bind(...), 'env::__syscall_bind'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_connect(...), 'env::__syscall_connect'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_getpeername(...), 'env::__syscall_getpeername'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_getsockname(...), 'env::__syscall_getsockname'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_getsockopt(...), 'env::__syscall_getsockopt'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_listen(...), 'env::__syscall_listen'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_recvfrom(...), 'env::__syscall_recvfrom'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_sendto(...), 'env::__syscall_sendto'), + makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_socket(...), 'env::__syscall_socket'), + makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_ftruncate64(...), 'env::__syscall_ftruncate64'), + makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_seek(...), 'wasi_snapshot_preview1::fd_seek'), + makeHostFunc('(i32) -> (i32)', hostFunc__env___mktime_js(...), 'env::_mktime_js'), + makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___localtime_js(...), 'env::_localtime_js'), + makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___gmtime_js(...), 'env::_gmtime_js'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env___munmap_js(...), 'env::_munmap_js'), + makeHostFunc('(i32, i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env___mmap_js(...), 'env::_mmap_js'), +]; +$store = Store::empty(); +$externVals = []; +foreach ($hostFuncs as $hostFunc) { + $store->funcs[] = $hostFunc; + $externVals[] = ExternVal::Func(\count($store->funcs) - 1); +} +$runtime = Runtime::instantiate($store, $module, $externVals); +$codePtr = allocateStringOnWasmMemory($runtime, PHP_HELLO_WORLD); + +$results = $runtime->invoke("php_wasm_run", [$codePtr]); +\assert(\count($results) === 1); +$exitCode = $results[0]; +\assert(\is_int($exitCode)); + +function dumpMemory(MemInst $mem): void +{ + $buf = ''; + $s = $mem->size(); + for ($j = 0; $j < $s; $j++) { + $c = $mem->loadByte($j); + \assert($c !== null); + $buf .= \chr($c); + if ($j % 1024 === 1023) { + fputs(STDOUT, $buf); + $buf = ""; + } + } + fputs(STDOUT, $buf); +} + +function allocateStringOnWasmMemory(Runtime $runtime, string $str): int +{ + // Plus 1 for the null terminator in C. + $size = \strlen($str) + 1; + $outPtr = wasm_stackAlloc($runtime, $size); + copyStringToWasmMemory($runtime, $outPtr, $str); + return $outPtr; +} + +function wasm_stackAlloc(Runtime $runtime, int $size): int +{ + $results = $runtime->invoke("stackAlloc", [$size]); + \assert(\count($results) === 1); + $result = $results[0]; + \assert(\is_int($result)); + return $result; +} + +function wasm_stackSave(Runtime $runtime): int +{ + $results = $runtime->invoke("stackSave", []); + \assert(\count($results) === 1); + $result = $results[0]; + \assert(\is_int($result)); + return $result; +} + +function copyStringToWasmMemory(Runtime $runtime, int $dst, string $src): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + for ($i = 0; $i < \strlen($src); $i++) { + $ok = $mem->storeByte($dst + $i, \ord($src[$i])); + \assert($ok); + } + // Terminate the string with a null byte for interoperation with C. + $ok = $mem->storeByte($dst + \strlen($src), 0); + \assert($ok); +} + +function makeHostFunc(string $typeDef, callable $fn, string $fnName): FuncInst +{ + $stringToType = fn (string $s) => match ($s) { + 'i32' => ValType::NumType(NumType::I32), + 'i64' => ValType::NumType(NumType::I64), + 'f32' => ValType::NumType(NumType::F32), + 'f64' => ValType::NumType(NumType::F64), + default => throw new \RuntimeException('Invalid type: ' . $s), + }; + preg_match('/^\(([^)]*)\) -> \(([^)]*)\)$/', $typeDef, $matches); + $paramsDef = $matches[1]; + $resultsDef = $matches[2]; + $params = array_map($stringToType, $paramsDef === '' ? [] : explode(', ', $paramsDef)); + $results = array_map($stringToType, $resultsDef === '' ? [] : explode(', ', $resultsDef)); + $type = new FuncType(new ResultType($params), new ResultType($results)); + return FuncInst::Host($type, function ($runtime) use ($fn, $fnName) { + // echo "TRACE: $fnName BEGIN\n"; + $fn($runtime); + // echo "TRACE: $fnName END\n"; + }); +} + +function getWasmTableEntry(Runtime $runtime, int $funcPtr): int +{ + static $wasmTable = null; + + if ($wasmTable === null) { + $wasmTable = $runtime->getExportedTable('__indirect_function_table'); + \assert($wasmTable !== null); + } + + $func = $wasmTable->elem[$funcPtr] ?? null; + \assert($func instanceof Refs\RefFunc, "Expected RefFunc, but got " . \get_class($func)); + return $func->addr; +} + +function convertI32PairToI53Checked(int $lo, int $hi): ?int +{ + return $lo + hi * 4294967296; +} + +function syscallGetStr(Runtime $runtime, int $ptr): string +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $str = ''; + for ($i = $ptr; $mem->loadByte($i) !== 0; $i++) { + $c = $mem->loadByte($i); + \assert($c !== null); + $str .= \chr($c); + } + return $str; +} + +function stringToUTF8(Runtime $runtime, string $s, int $ptr, $len): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + for ($i = 0; $i < $len; $i++) { + if ($i < \strlen($s)) { + $mem->storeByte($ptr + $i, \ord($s[$i])); + } else { + $mem->storeByte($ptr + $i, 0); + } + } +} + +function heap8Write(Runtime $runtime, int $ptr, int $value): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $mem->storeI32_s8($ptr, $value); +} + +function heap16Write(Runtime $runtime, int $ptr, int $value): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $mem->storeI32_s16($ptr, $value); +} + +function heap32Write(Runtime $runtime, int $ptr, int $value): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $mem->storeI32_s32($ptr, $value); +} + +function heapU32Write(Runtime $runtime, int $ptr, int $value): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $mem->storeI32_s32($ptr, $value); +} + +function heap64Write(Runtime $runtime, int $ptr, int $value): void +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + $mem->storeI64_s64($ptr, $value); +} + +function syscallDoStat(Runtime $runtime, callable $func, string $path, int $buf): void +{ + $stat = $func($path); + + heap32Write($runtime, $buf, $stat->dev); + heap32Write($runtime, $buf + 4, $stat->mode); + heapU32Write($runtime, $buf + 8, $stat->nlink); + heap32Write($runtime, $buf + 12, $stat->uid); + heap32Write($runtime, $buf + 16, $stat->gid); + heap32Write($runtime, $buf + 20, $stat->rdev); + heap64Write($runtime, $buf + 24, $stat->size); + heap32Write($runtime, $buf + 32, 4096); + heap32Write($runtime, $buf + 36, $stat->blocks); + $atime = $stat->atime; + heap64Write($runtime, $buf + 40, $atime); + heapU32Write($runtime, $buf + 48, ($atime % 1000) * 1000); + $mtime = $stat->mtime; + heap64Write($runtime, $buf + 56, $mtime); + heapU32Write($runtime, $buf + 64, ($mtime % 1000) * 1000); + $ctime = $stat->ctime; + heap64Write($runtime, $buf + 72, $ctime); + heapU32Write($runtime, $buf + 80, ($ctime % 1000) * 1000); + heap64Write($runtime, $buf + 88, $stat->ino); +} + +function syscallCalculateAt(Runtime $runtime, int $dirfd, string $path): string +{ + if ($path[0] === '/') { + return $path; + } + if ($dirfd === -100) { + $dir = getcwd(); + \assert($dir !== false); + } else { + throw new \RuntimeException("syscallCalculateAt: not implemented ($dirfd)"); + } + if ($path === '.') { + return $dir; + } else { + return $dir . '/' . $path; + } +} + +function fsStat(string $path, bool $dontFollow): object +{ + if ($path === 'php://stdin') { + return (object)[ + 'dev' => 0, + 'mode' => 0, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 0, + 'blocks' => 0, + 'ino' => 0, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + ]; + } else if ($path === 'php://stdout') { + return (object)[ + 'dev' => 0, + 'mode' => 0, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 0, + 'blocks' => 0, + 'ino' => 1, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + ]; + } else if ($path === 'php://stderr') { + return (object)[ + 'dev' => 0, + 'mode' => 0, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 0, + 'blocks' => 0, + 'ino' => 2, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + ]; + } + + $phpStat = $dontFollow ? lstat($path) : stat($path); + assert($phpStat !== false); + return (object)[ + 'dev' => $phpStat['dev'], + 'mode' => $phpStat['mode'], + 'nlink' => $phpStat['nlink'], + 'uid' => $phpStat['uid'], + 'gid' => $phpStat['gid'], + 'rdev' => $phpStat['rdev'], + 'size' => $phpStat['size'], + 'blocks' => $phpStat['blocks'], + 'ino' => $phpStat['ino'], + 'atime' => $phpStat['atime'] * 1000, + 'mtime' => $phpStat['mtime'] * 1000, + 'ctime' => $phpStat['ctime'] * 1000, + ]; +} + +function fsLstat(string $path): object +{ + return fsStat($path, true); +} + +final class VFile { + public ?array $getdents = null; + + public function __construct( + public readonly int $fd, + /** + * @param resource $fp + */ + public readonly mixed $fp, + public readonly int $flags, + public readonly string $path, + ) {} + + public function seek(int $offset, int $whence): int + { + if ($whence === 0) { + fseek($this->fp, $offset, SEEK_SET); + } elseif ($whence === 1) { + fseek($this->fp, $offset, SEEK_CUR); + } elseif ($whence === 2) { + fseek($this->fp, $offset, SEEK_END); + } else { + throw new \RuntimeException("VFile::seek: invalid whence"); + } + $pos = ftell($this->fp); + return $pos === false ? 0 : $pos; + } + + public function read(Runtime $runtime, int $len): string + { + return fread($this->fp, $len); + } + + public function close(): void + { + fclose($this->fp); + } +} + +function fsOpen(string $path, int $flags, int $mode): ?int +{ + global $fdTable; + if (!isset($fdTable)) { + $fdTable = []; + } + $fp = @fopen($path, 'r'); + if ($fp === false) { + return null; + } + $nextFd = count($fdTable) + 10; + $fdTable[$nextFd] = new VFile( + $nextFd, + $fp, + $flags, + $path, + ); + return $nextFd; +} + +function fsDup(int $fd): ?int +{ + global $fdTable; + if (!isset($fdTable)) { + return null; + } + $nextFd = count($fdTable) + 10; + if ($fd === 0) { + $fp = fopen('php://stdin', 'r'); + $fdTable[$nextFd] = new VFile( + $nextFd, + $fp, + 0, + 'php://stdin', + ); + } else if ($fd === 1) { + $fp = fopen('php://stdout', 'w'); + $fdTable[$nextFd] = new VFile( + $nextFd, + $fp, + 0, + 'php://stdout', + ); + } else if ($fd === 2) { + $fp = fopen('php://stderr', 'w'); + $fdTable[$nextFd] = new VFile( + $nextFd, + $fp, + 0, + 'php://stderr', + ); + } else { + $file = $fdTable[$fd]; + $fp = $file->fp; + $fdTable[$nextFd] = new VFile( + $nextFd, + $fp, + $file->flags, + $file->path, + ); + } + return $nextFd; +} + +function fsGetVFileFromFd(int $fd): ?VFile +{ + global $fdTable; + return $fdTable[$fd] ?? null; +} + +function fsGetPathFromFd(int $fd): ?string +{ + return fsGetVFileFromFd($fd)?->path; +} + +function fsGetFpFromFd(int $fd): mixed +{ + return fsGetVFileFromFd($fd)?->fp; +} + +function fsGetFlagsFromFd(int $fd): ?int +{ + return fsGetVFileFromFd($fd)?->flags; +} + +function fsReaddir(string $p): array +{ + $dir = opendir($p); + $entries = []; + while (($entry = readdir($dir)) !== false) { + $entries[] = $entry; + } + closedir($dir); + return $entries; +} + +function fsLookupParentPath(string $p): string +{ + return realpath($p . '/..'); +} + +function fsLookupChild(string $p, string $c): string +{ + return realpath($p . '/' . $c); +} + +function alignMemory(int $size, int $alignment): int +{ + return (int)ceil($size / $alignment) * $alignment; +} + +function _emscripten_builtin_memalign(Runtime $runtime, int $alignment, int $size): int +{ + $results = $runtime->invoke("emscripten_builtin_memalign", [$alignment, $size]); + \assert(\count($results) === 1); + $result = $results[0]; + \assert(\is_int($result)); + return $result; +} + +function zeroMemory(Runtime $runtime, int $ptr, int $len): int +{ + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + for ($i = 0; $i < $len; $i++) { + $mem->storeByte($ptr + $i, 0); + } + return $ptr; +} + +function mmapAlloc(Runtime $runtime, int $len): int +{ + $len = alignMemory($len, 65536); + $ptr = _emscripten_builtin_memalign($runtime, 65536, $len); + if ($ptr === 0) { + return 0; + } + return zeroMemory($runtime, $ptr, $len); +} + +function fsMmap(Runtime $runtime, int $fd, int $len, int $offset, int $prot, int $flags): array +{ + global $fdTable; + if (!isset($fdTable[$fd])) { + throw new \RuntimeException("fsMmap: invalid fd"); + } + $file = $fdTable[$fd]; + + $buf = stream_get_contents($file->fp); + + $ptr = mmapAlloc($runtime, $len); + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + for ($i = 0; $i < $len; $i++) { + $mem->storeByte($ptr + $i, ord($buf[$i])); + } + + return [$ptr, 1]; +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iii(Runtime $runtime): void +{ + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iiiii(Runtime $runtime): void +{ + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32) -> () +function hostFunc__env__invoke_v(Runtime $runtime): void +{ + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iiii(Runtime $runtime): void +{ + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env__invoke_ii(Runtime $runtime): void +{ + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->invokeByFuncAddr($func); +} + +// Type: () -> () +function hostFunc__env__abort(Runtime $runtime): void +{ + throw new \RuntimeException('env::abort: not implemented'); +} + +// Type: (i32) -> () +function hostFunc__env__exit(Runtime $runtime): void +{ + throw new \RuntimeException('env::exit: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> () +function hostFunc__env__invoke_viii(Runtime $runtime): void +{ + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32) -> () +function hostFunc__env__invoke_vii(Runtime $runtime): void +{ + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32) -> () +function hostFunc__env__invoke_vi(Runtime $runtime): void +{ + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32) -> (i32) +function hostFunc__env__invoke_i(Runtime $runtime): void +{ + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iiiiiii(Runtime $runtime): void +{ + $a6 = $runtime->stack->popInt(); + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->stack->pushValue($a6); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32) -> () +function hostFunc__env____assert_fail(Runtime $runtime): void +{ + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32) -> () +function hostFunc__env__invoke_viiii(Runtime $runtime): void +{ + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> () +function hostFunc__env__invoke_viiiii(Runtime $runtime): void +{ + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iiiiii(Runtime $runtime): void +{ + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__invoke_iiiiiiiiii(Runtime $runtime): void +{ + $a9 = $runtime->stack->popInt(); + $a8 = $runtime->stack->popInt(); + $a7 = $runtime->stack->popInt(); + $a6 = $runtime->stack->popInt(); + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->stack->pushValue($a6); + $runtime->stack->pushValue($a7); + $runtime->stack->pushValue($a8); + $runtime->stack->pushValue($a9); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env__strftime(Runtime $runtime): void +{ + throw new \RuntimeException('env::strftime: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env__getaddrinfo(Runtime $runtime): void +{ + throw new \RuntimeException('env::getaddrinfo: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__gethostbyname_r(Runtime $runtime): void +{ + throw new \RuntimeException('env::gethostbyname_r: not implemented'); +} + +// Type: () -> (i32) +function hostFunc__env__getdtablesize(Runtime $runtime): void +{ + throw new \RuntimeException('env::getdtablesize: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env__getprotobyname(Runtime $runtime): void +{ + throw new \RuntimeException('env::getprotobyname: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env__getprotobynumber(Runtime $runtime): void +{ + throw new \RuntimeException('env::getprotobynumber: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env__strptime(Runtime $runtime): void +{ + throw new \RuntimeException('env::strptime: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env__getnameinfo(Runtime $runtime): void +{ + throw new \RuntimeException('env::getnameinfo: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32) -> () +function hostFunc__env__invoke_viiiiii(Runtime $runtime): void +{ + $a6 = $runtime->stack->popInt(); + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popInt(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->stack->pushValue($a6); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, f64, i32, i32) -> () +function hostFunc__env__invoke_viidii(Runtime $runtime): void +{ + $a5 = $runtime->stack->popInt(); + $a4 = $runtime->stack->popInt(); + $a3 = $runtime->stack->popFloat(); + $a2 = $runtime->stack->popInt(); + $a1 = $runtime->stack->popInt(); + $index = $runtime->stack->popInt(); + $sp = wasm_stackSave($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32) -> (i32) +function hostFunc__env__getcontext(Runtime $runtime): void +{ + throw new \RuntimeException('env::getcontext: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> () +function hostFunc__env__makecontext(Runtime $runtime): void +{ + throw new \RuntimeException('env::makecontext: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env__swapcontext(Runtime $runtime): void +{ + throw new \RuntimeException('env::swapcontext: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__environ_sizes_get(Runtime $runtime): void +{ + throw new \RuntimeException('wasi_snapshot_preview1::environ_sizes_get: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__environ_get(Runtime $runtime): void +{ + throw new \RuntimeException('wasi_snapshot_preview1::environ_get: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_fcntl64(Runtime $runtime): void +{ + $varargs = $runtime->stack->popInt(); + $cmd = $runtime->stack->popInt(); + $fd = $runtime->stack->popInt(); + + switch ($cmd) { + case 0: + throw new \RuntimeException("env::__syscall_fcntl64: command $cmd not implemented"); + case 1: + case 2: + $runtime->stack->pushValue(0); + return; + case 3: + $runtime->stack->pushValue(fsGetFlagsFromFd($fd)); + return; + case 4: + throw new \RuntimeException("env::__syscall_fcntl64: command $cmd not implemented"); + case 5: + throw new \RuntimeException("env::__syscall_fcntl64: command $cmd not implemented"); + case 6: + case 7: + $runtime->stack->pushValue(0); + return; + case 16: + case 8: + $runtime->stack->pushValue(-28); + return; + case 9: + // setErrno(28); + $runtime->stack->pushValue(-1); + return; + default: + $runtime->stack->pushValue(-28); + return; + } +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_ioctl(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_ioctl: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_close(Runtime $runtime): void +{ + $fd = $runtime->stack->popInt(); + $file = fsGetVFileFromFd($fd); + assert($file !== null); + $file->close(); + $runtime->stack->pushValue(0); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_read(Runtime $runtime): void +{ + // Output pointer to the number of bytes written. + $pnum = $runtime->stack->popInt(); + // Length of the array of iov structs. + $iovcnt = $runtime->stack->popInt(); + // Pointer to the array of iov structs. + $iov = $runtime->stack->popInt(); + // File descripter. + $fd = $runtime->stack->popInt(); + + $file = fsGetVFileFromFd($fd); + assert($file !== null); + + // struct iov { + // ptr: u32, pointer to the data + // len: u32 + // } + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + + $nRead = 0; + for ($i = 0; $i < $iovcnt; $i++) { + $ptr = $mem->loadI32_s32($iov + $i * 8); + \assert($ptr !== null); + $len = $mem->loadI32_s32($iov + $i * 8 + 4); + \assert($len !== null); + $buf = $file->read($runtime, $len); + if ($buf === false) { + $nRead = -1; + break; + } + $curr = strlen($buf); + if ($curr <= 0) { + $nRead = -1; + break; + } + // echo "fd_read(fd=$fd, iov=$iov, iovcnt=$iovcnt, pnum=$pnum) = { p=$ptr, l=$len }\n"; + for ($k = 0; $k < $curr; $k++) { + $mem->storeByte($ptr + $k, ord($buf[$k])); + // echo " [$k] = ord($buf[$k])\n"; + } + $nRead += $curr; + if ($curr < $len) { + break; + } + } + + $mem->storeI32_s32($pnum, $nRead); + + $runtime->stack->pushValue(0); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_write(Runtime $runtime): void +{ + // Output pointer to the number of bytes written. + $pnum = $runtime->stack->popInt(); + // Length of the array of iov structs. + $iovcnt = $runtime->stack->popInt(); + // Pointer to the array of iov structs. + $iov = $runtime->stack->popInt(); + // File descripter. + $fd = $runtime->stack->popInt(); + + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + + // struct iov { + // ptr: u32, pointer to the data + // len: u32 + // } + $nWritten = 0; + for ($i = 0; $i < $iovcnt; $i++) { + $ptr = $mem->loadI32_s32($iov + $i * 8); + \assert($ptr !== null); + $len = $mem->loadI32_s32($iov + $i * 8 + 4); + // echo "fd_write($iovcnt, $iov) [$i] = { p=$ptr, l=$len };\n"; + \assert($len !== null); + $buf = ''; + for ($j = 0; $j < $len; $j++) { + $c = $mem->loadByte($ptr + $j); + \assert($c !== null); + $buf .= \chr($c); + } + if ($fd === 1) { + fputs(STDOUT, $buf); + } else { + fputs(STDERR, $buf); + } + $nWritten += $len; + } + $mem->storeI32_s32($pnum, $nWritten); + + $runtime->stack->pushValue(0); +} + +// Type: (i32) -> () +function hostFunc__wasi_snapshot_preview1__proc_exit(Runtime $runtime): void +{ + throw new \RuntimeException('wasi_snapshot_preview1::proc_exit: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_faccessat(Runtime $runtime): void +{ + $flags = $runtime->stack->popInt(); + $amode = $runtime->stack->popInt(); + $path = $runtime->stack->popInt(); + $dirfd = $runtime->stack->popInt(); + + $path = syscallGetStr($runtime, $path); + $path = syscallCalculateAt($runtime, $dirfd, $path); + + // Always allow accesses. + $runtime->stack->pushValue(0); +} + +// Type: (i32) -> (i32) +function hostFunc__env____syscall_chdir(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_chdir: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_chmod(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_chmod: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_fchownat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_fchownat: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env____syscall_dup(Runtime $runtime): void +{ + $oldFd = $runtime->stack->popInt(); + $newFd = fsDup($oldFd); + $runtime->stack->pushValue($newFd); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_dup3(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_dup3: not implemented'); +} + +// Type: (i32, i32, i32) -> () +function hostFunc__env__emscripten_memcpy_js(Runtime $runtime): void +{ + $num = $runtime->stack->popInt(); + $src = $runtime->stack->popInt(); + $dest = $runtime->stack->popInt(); + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + for ($i = 0; $i < $num; $i++) { + $byte = $mem->loadByte($src + $i); + \assert($byte !== null); + $mem->storeByte($dest + $i, $byte); + } +} + +// Type: () -> (f64) +function hostFunc__env__emscripten_date_now(Runtime $runtime): void +{ + $t = round(microtime(true) * 1000); + $runtime->stack->pushValue($t); +} + +// Type: () -> (i32) +function hostFunc__env___emscripten_get_now_is_monotonic(Runtime $runtime): void +{ + throw new \RuntimeException('env::_emscripten_get_now_is_monotonic: not implemented'); +} + +// Type: () -> (f64) +function hostFunc__env__emscripten_get_now(Runtime $runtime): void +{ + throw new \RuntimeException('env::emscripten_get_now: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env____syscall_fdatasync(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_fdatasync: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_openat(Runtime $runtime): void +{ + $varargs = $runtime->stack->popInt(); + $flags = $runtime->stack->popInt(); + $path = $runtime->stack->popInt(); + $dirfd = $runtime->stack->popInt(); + + $path = syscallGetStr($runtime, $path); + $path = syscallCalculateAt($runtime, $dirfd, $path); + + $mem = $runtime->getExportedMemory('memory'); + \assert($mem !== null); + + if ($varargs !== 0) { + $mode = $mem->loadI32_s32($varargs); + $varargs += 4; + } else { + $mode = 0; + } + + $fd = fsOpen($path, $flags, $mode); + if ($fd !== null) { + $runtime->stack->pushValue($fd); + } else { + // no such file + $runtime->stack->pushValue(-44); + } +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_fstat64(Runtime $runtime): void +{ + $buf = $runtime->stack->popInt(); + $fd = $runtime->stack->popInt(); + $path = fsGetPathFromFd($fd); + assert($path !== null); + syscallDoStat($runtime, fn ($path) => fsStat($path, false), $path, $buf); + $runtime->stack->pushValue(0); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_stat64(Runtime $runtime): void +{ + $buf = $runtime->stack->popInt(); + $path = $runtime->stack->popInt(); + $path = syscallGetStr($runtime, $path); + syscallDoStat($runtime, fn ($path) => fsStat($path, false), $path, $buf); + $runtime->stack->pushValue(0); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_newfstatat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_newfstatat: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_lstat64(Runtime $runtime): void +{ + $buf = $runtime->stack->popInt(); + $path = $runtime->stack->popInt(); + $path = syscallGetStr($runtime, $path); + syscallDoStat($runtime, fsLstat(...), $path, $buf); + $runtime->stack->pushValue(0); +} + +// Type: (i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_sync(Runtime $runtime): void +{ + throw new \RuntimeException('wasi_snapshot_preview1::fd_sync: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_getcwd(Runtime $runtime): void +{ + $size = $runtime->stack->popInt(); + $bufPtr = $runtime->stack->popInt(); + if ($size === 0) { + $runtime->stack->pushValue(-28); + return; + } + $cwd = getcwd(); + \assert($cwd !== false); + $cwdLen = \strlen($cwd) + 1; + if ($size < $cwdLen) { + $runtime->stack->pushValue(-68); + return; + } + copyStringToWasmMemory($runtime, $bufPtr, $cwd); + $runtime->stack->pushValue($cwdLen); +} + +// Type: (i32) -> () +function hostFunc__env__emscripten_err(Runtime $runtime): void +{ + throw new \RuntimeException('env::emscripten_err: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_fdstat_get(Runtime $runtime): void +{ + throw new \RuntimeException('wasi_snapshot_preview1::fd_fdstat_get: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_mkdirat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_mkdirat: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env____syscall_pipe(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_pipe: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_poll(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_poll: not implemented'); +} + +// Type: (i32, i32) -> () +function hostFunc__env____call_sighandler(Runtime $runtime): void +{ + throw new \RuntimeException('env::__call_sighandler: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_getdents64(Runtime $runtime): void +{ + $count = $runtime->stack->popInt(); + $dirp = $runtime->stack->popInt(); + $fd = $runtime->stack->popInt(); + + $file = fsGetVFileFromFd($fd); + + if ($file->getdents === null) { + $file->getdents = fsReaddir($file->path); + } + + $struct_size = 280; + $pos = 0; + $off = $file->seek(0, 1); + + $idx = (int)floor($off / $struct_size); + + while ($idx < count($file->getdents) && $pos + $struct_size <= $count) { + $name = $file->getdents[$idx]; + if ($name === '.') { + $id = fsStat($file->path, true)->ino; + $type = 4; + } else if ($name === '..') { + $lookup = fsLookupParentPath($file->path); + $id = fsStat($lookup, true)->ino; + $type = 4; + } else { + $child = fsLookupChild($file->path, $name); + $id = fsStat($child, true)->ino; + $type = is_dir($child) ? 4 : (is_file($child) ? 8 : 10); + } + heap64Write($runtime, $dirp + $pos, $id); + heap64Write($runtime, $dirp + $pos + 8, ($idx + 1) * $struct_size); + heap16Write($runtime, $dirp + $pos + 16, $struct_size); + heap8Write($runtime, $dirp + $pos + 18, $type); + stringToUTF8($runtime, $name, $dirp + $pos + 19, 256); + $pos += $struct_size; + $idx += 1; + } + $file->seek($idx * $struct_size, 0); + + $runtime->stack->pushValue($pos); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_readlinkat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_readlinkat: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_renameat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_renameat: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env____syscall_rmdir(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_rmdir: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall__newselect(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall__newselect: not implemented'); +} + +// Type: (i32, f64) -> (i32) +function hostFunc__env___setitimer_js(Runtime $runtime): void +{ + throw new \RuntimeException('env::_setitimer_js: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_statfs64(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_statfs64: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_symlink(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_symlink: not implemented'); +} + +// Type: () -> (i32) +function hostFunc__env__emscripten_get_heap_max(Runtime $runtime): void +{ + throw new \RuntimeException('env::emscripten_get_heap_max: not implemented'); +} + +// Type: (i32, i32, i32) -> () +function hostFunc__env___tzset_js(Runtime $runtime): void +{ + $tzname = $runtime->stack->popInt(); + $daylight = $runtime->stack->popInt(); + $timezone = $runtime->stack->popInt(); + // Do nothing ;) +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_unlinkat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_unlinkat: not implemented'); +} + +// Type: (i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_utimensat(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_utimensat: not implemented'); +} + +// Type: (i32) -> (i32) +function hostFunc__env__emscripten_resize_heap(Runtime $runtime): void +{ + throw new \RuntimeException('env::emscripten_resize_heap: not implemented'); +} + +// Type: () -> () +function hostFunc__env___emscripten_throw_longjmp(Runtime $runtime): void +{ + throw new \RuntimeException('env::_emscripten_throw_longjmp: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_accept4(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_accept4: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_bind(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_bind: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_connect(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_connect: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_getpeername(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_getpeername: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_getsockname(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_getsockname: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_getsockopt(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_getsockopt: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_listen(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_listen: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_recvfrom(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_recvfrom: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_sendto(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_sendto: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env____syscall_socket(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_socket: not implemented'); +} + +// Type: (i32, i32, i32) -> (i32) +function hostFunc__env____syscall_ftruncate64(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_ftruncate64: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_seek(Runtime $runtime): void +{ + $newOffset = $runtime->stack->popInt(); + $whence = $runtime->stack->popInt(); + $offset_high = $runtime->stack->popInt(); + $offset_low = $runtime->stack->popInt(); + $fd = $runtime->stack->popInt(); + + $offset = $offset_low + $offset_high * 4294967296; + $file = fsGetVFileFromFd($fd); + $pos = $file->seek($offset, $whence); + heap64Write($runtime, $newOffset, $pos); + + $runtime->stack->pushValue(0); +} + +// Type: (i32) -> (i32) +function hostFunc__env___mktime_js(Runtime $runtime): void +{ + throw new \RuntimeException('env::_mktime_js: not implemented'); +} + +// Type: (i32, i32, i32) -> () +function hostFunc__env___localtime_js(Runtime $runtime): void +{ + throw new \RuntimeException('env::_localtime_js: not implemented'); +} + +// Type: (i32, i32, i32) -> () +function hostFunc__env___gmtime_js(Runtime $runtime): void +{ + throw new \RuntimeException('env::_gmtime_js: not implemented'); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env___munmap_js(Runtime $runtime): void +{ + // Do nothing. + $_7 = $runtime->stack->popInt(); + $_6 = $runtime->stack->popInt(); + $_5 = $runtime->stack->popInt(); + $_4 = $runtime->stack->popInt(); + $_3 = $runtime->stack->popInt(); + $_2 = $runtime->stack->popInt(); + $_1 = $runtime->stack->popInt(); + + $runtime->stack->pushValue(0); +} + +// Type: (i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) +function hostFunc__env___mmap_js(Runtime $runtime): void +{ + $addr = $runtime->stack->popInt(); + $allocated = $runtime->stack->popInt(); + $offset_high = $runtime->stack->popInt(); + $offset_low = $runtime->stack->popInt(); + $fd = $runtime->stack->popInt(); + $flags = $runtime->stack->popInt(); + $prot = $runtime->stack->popInt(); + $len = $runtime->stack->popInt(); + + $offset = $offset_low + $offset_high * 4294967296; + + [$resultPtr, $resultAllocated] = fsMmap($runtime, $fd, $len, $offset, $prot, $flags); + heap32Write($runtime, $allocated, $resultAllocated); + heapU32Write($runtime, $addr, $resultPtr); + + $runtime->stack->pushValue(0); +} diff --git a/examples/rubyvm-on-php-on-wasm/php-wasm.wasm b/examples/rubyvm-on-php-on-wasm/php-wasm.wasm Binary files differnew file mode 100755 index 0000000..8e91021 --- /dev/null +++ b/examples/rubyvm-on-php-on-wasm/php-wasm.wasm |
