diff --git a/packages/docs/site/docs/main/resources.md b/packages/docs/site/docs/main/resources.md index 3c1d09b58e..63f07a8e81 100644 --- a/packages/docs/site/docs/main/resources.md +++ b/packages/docs/site/docs/main/resources.md @@ -22,70 +22,70 @@ There's a set of redirections in place to make it easier the access to some of t ## Frequently sought links -- [Demo](https://playground.wordpress.net/) -- [GitHub Repository](https://github.com/WordPress/wordpress-playground) -- [Documentation](https://wordpress.github.io/wordpress-playground/) -- [Playground tools Repository](https://github.com/WordPress/playground-tools) +- [Demo](https://playground.wordpress.net/) +- [GitHub Repository](https://github.com/WordPress/wordpress-playground) +- [Documentation](https://wordpress.github.io/wordpress-playground/) +- [Playground tools Repository](https://github.com/WordPress/playground-tools) ## Apps built with WordPress Playground -- [Official demo](https://playground.wordpress.net/) and the [showcase](https://developer.wordpress.org/playground) app – install a theme, try out a plugin, create a few pages, export what you've built -- [@wp-playground/cli](https://www.npmjs.com/package/@wp-playground/cli) – a CLI tool for instant WordPress dev environment -- [WordPress Playground for VS Code](https://marketplace.visualstudio.com/items?itemName=WordPressPlayground.wordpress-playground) -- Live Translations: [App](https://translate.wordpress.org/projects/wp-plugins/friends/dev/pl/default/playground/), [announcement](https://make.wordpress.org/polyglots/2023/04/19/wp-translation-playground/), [more details](https://make.wordpress.org/polyglots/2023/05/08/translate-live-updates-to-the-translation-playground/) -- [Interactive code block](https://wordpress.org/plugins/interactive-code-block/) which powers the [HTML Tag Processor tutorial](https://adamadam.blog/2023/02/16/how-to-modify-html-in-a-php-wordpress-plugin-using-the-new-tag-processor-api/) and the [Playground JS API tutorial](https://wordpress.github.io/wordpress-playground/developers/apis/javascript-api/) -- [Gutenberg Pull Request previewer](https://playground.wordpress.net/gutenberg.html) -- [Notifications plugin live demo](https://johnhooks.io/playground-experiment/) -- [GraphQL REPL](https://www.wpgraphql.com/2023/06/15/announcing-the-wpgraphql-repl) -- [Blocknotes](https://twitter.com/adamzielin/status/1669478239771799552) – the first ever iOS app running WordPress on your phone -- [Playground embedder](https://joost.blog/embedded-playground/) to embed Playground examples in WordPress.org documentation using shortcodes -- [Plugin demos on wp.org](https://gist.github.com/adamziel/0fe3ffc1fb5202a907a87d055ee37135) – a user script that adds a "demo" tab to plugin pages on WordPress.org -- [WordPress Pull Request previewer](https://playground.wordpress.net/wordpress.html) -- [Synchronization between two Playgrounds](https://playground.wordpress.net/demos/sync.html) -- [Time Travel](https://playground.wordpress.net/demos/time-traveling.html) -- [WP-CLI](https://playground.wordpress.net/demos/wp-cli.html) -- [PHP implementation of Blueprints](https://playground.wordpress.net/demos/php-blueprints.html) +- [Official demo](https://playground.wordpress.net/) and the [showcase](https://developer.wordpress.org/playground) app – install a theme, try out a plugin, create a few pages, export what you've built +- [@wp-playground/cli](https://www.npmjs.com/package/@wp-playground/cli) – a CLI tool for instant WordPress dev environment +- [WordPress Playground for VS Code](https://marketplace.visualstudio.com/items?itemName=WordPressPlayground.wordpress-playground) +- Live Translations: [App](https://translate.wordpress.org/projects/wp-plugins/friends/dev/pl/default/playground/), [announcement](https://make.wordpress.org/polyglots/2023/04/19/wp-translation-playground/), [more details](https://make.wordpress.org/polyglots/2023/05/08/translate-live-updates-to-the-translation-playground/) +- [Interactive code block](https://wordpress.org/plugins/interactive-code-block/) which powers the [HTML Tag Processor tutorial](https://adamadam.blog/2023/02/16/how-to-modify-html-in-a-php-wordpress-plugin-using-the-new-tag-processor-api/) and the [Playground JS API tutorial](https://wordpress.github.io/wordpress-playground/developers/apis/javascript-api/) +- [Gutenberg Pull Request previewer](https://playground.wordpress.net/gutenberg.html) +- [Notifications plugin live demo](https://johnhooks.io/playground-experiment/) +- [GraphQL REPL](https://www.wpgraphql.com/2023/06/15/announcing-the-wpgraphql-repl) +- [Blocknotes](https://twitter.com/adamzielin/status/1669478239771799552) – the first ever iOS app running WordPress on your phone +- [Playground embedder](https://joost.blog/embedded-playground/) to embed Playground examples in WordPress.org documentation using shortcodes +- [Plugin demos on wp.org](https://gist.github.com/adamziel/0fe3ffc1fb5202a907a87d055ee37135) – a user script that adds a "demo" tab to plugin pages on WordPress.org +- [WordPress Pull Request previewer](https://playground.wordpress.net/wordpress.html) +- [Synchronization between two Playgrounds](https://playground.wordpress.net/demos/sync.html) +- [Time Travel](https://playground.wordpress.net/demos/time-traveling.html) +- [WP-CLI](https://playground.wordpress.net/demos/wp-cli.html) +- [PHP implementation of Blueprints](https://playground.wordpress.net/demos/php-blueprints.html) ## Reading materials -- [Build in-browser WordPress experiences with WordPress Playground and WebAssembly](https://web.dev/wordpress-playground/) -- [WordPress Playground on developer.wordpress.org](https://developer.wordpress.org/playground) -- [In-Browser WordPress Tech Demos: WordPress Development with WordPress Playground](https://make.wordpress.org/core/2023/04/13/in-browser-wordpress-tech-demos-wordpress-development-with-wordpress-playground/) -- [Initial announcement on make.wordpress.org](https://make.wordpress.org/core/2022/09/23/client-side-webassembly-wordpress-with-no-server/) -- [Hackernews discussion](https://news.ycombinator.com/item?id=32960560) +- [Build in-browser WordPress experiences with WordPress Playground and WebAssembly](https://web.dev/wordpress-playground/) +- [WordPress Playground on developer.wordpress.org](https://developer.wordpress.org/playground) +- [In-Browser WordPress Tech Demos: WordPress Development with WordPress Playground](https://make.wordpress.org/core/2023/04/13/in-browser-wordpress-tech-demos-wordpress-development-with-wordpress-playground/) +- [Initial announcement on make.wordpress.org](https://make.wordpress.org/core/2022/09/23/client-side-webassembly-wordpress-with-no-server/) +- [Hackernews discussion](https://news.ycombinator.com/item?id=32960560) ## Videos -- Developer Hours Videos: - - [Americas Region (May 23,2023)](https://wordpress.tv/2023/05/23/developer-hours-wordpress-playground-americas/) - - [APAC/EMEA Region (May 24,2023)](https://wordpress.tv/2023/05/24/developer-hours-wordpress-playground-apac-emea/) - - [Creating WordPress Playground Blueprints for Testing and Demos (May 28, 2024)](https://wordpress.tv/2024/05/28/developer-hours-creating-wordpress-playground-blueprints-for-testing-and-demos/) by Birgit Pauli-Haack & Nick Diego - - [Developer Hours: Everything you need to know about WordPress Playground (Dec 17, 2024)](https://wordpress.tv/2024/12/17/developer-hours-everything-you-need-to-know-about-wordpress-playground/) by Nick Diego & Ryan Welcher -- [Playground at State of the Word](https://youtu.be/VeigCZuxnfY?t=2912) -- [Playground at WCEU 2023](https://www.youtube.com/watch?v=e-CwouzTGp4&t=26946s) -- [Watch "WordPress Playground: the ultimate learning, testing, & teaching tool for WordPress"](https://www.youtube.com/watch?v=dN_LaenY8bI) by Anne McCarthy -- [WordPress Playground for developers](https://wordpress.tv/2024/12/16/wordpress-playground-for-developers/) by Berislav Grgicak and Jonathan Bossenger -- [WordPress Playground Block code editor theme support](https://wordpress.tv/2024/10/05/wordpress-playground-block-code-editor-theme-support/) by Jonathan Bossenger -- [WordPress Playground – use WordPress without a server at WCEU 2024](https://wordpress.tv/2024/07/03/wordpress-playground-use-wordpress-without-a-server/) by Adam Zielinski -- [Code, Test, Repeat: Accelerating Development with WordPress Playground at WordCamp Larissa 2024](https://wordpress.tv/2024/12/13/code-test-repeat-accelerating-development-with-wordpress-playground/) by Uros Tasic -- [Liberating data with WordPress Playground in a Browser Extension at WordCamp Netherlands 2024](https://wordpress.tv/2024/12/24/liberating-data-with-wordpress-playground-in-a-browser-extension/) by Alex Kirk -- [Beyond the Playground: WordPress as a Tool and Product Builder at WCUS 2024](https://wordpress.tv/2024/10/10/beyond-the-playground-wordpress-as-a-tool-and-product-builder/) by Dennis Snell -- [Create a demo with Playground at WC Asia 2025](https://wordpress.tv/2025/04/30/create-a-demo-with-playground/) by Birgit Pauli-Haack -- [Dissecting WordPress Playground at WordCamp Nepal 2025](https://wordpress.tv/2025/04/30/dissecting-wordpress-playground/) by Sakar Upadhyaya Khatiwada -- [Building Automated Test with WordPress Playground at WCEU 2025](https://wordpress.tv/2025/06/07/building-automated-tests-with-wordpress-playground/)by Berislav Grgicak -- [From Zero to Demo: Mastering WordPress Playground Blueprints at WCEU 2025](https://wordpress.tv/2025/06/07/from-zero-to-demo-mastering-wordpress-playground-blueprints/) by Birgit Pauli-Haack -- [Playground at WordCamp Gliwice (in Polish)](https://www.youtube.com/watch?v=AUHklF9GdL8&list=PLiCne9CeL82_hGuJOAJlsc84WxVDSH-c9&index=4) by Adam Zielinski -- [WordPress Playground at WordCamp Wrocław 2024 (in Polish)](https://wordpress.tv/2024/12/02/wordpress-playground-przelom-w-wordpressie-2/) by Adam Zielinski -- [WordPress Playground at WordCamp Gdynia 2025 (in Polish)](https://wordpress.tv/2025/04/21/wordpress-playground/) by Magdalena Paciorek -- [Discovering Playground, the demo tool(in Spanish)](https://wordpress.tv/2024/08/09/descubriendo-playground-la-herramienta-para-hacer-demos/) by Alex Cuadra -- [WordPress Playground: Complete and functional WordPress installation(in Spanish)](https://wordpress.tv/2024/02/07/wordpress-playground-instalacion-completa-y-funcional-de-wordpress/) by Fernando García Rebolledo -- [Playground: A throwaway WordPress within your browser at WordCamp Madrid 2025(in Spanish)](https://wordpress.tv/2025/03/09/playground-un-wordpress-de-usar-y-tirar-dentro-de-tu-navegador/) by Álvaro Gómez Velasco -- [Use WordPress with just a browser! WordPress Playground Tutorial: Basic usage of Playground (in Japanese)](https://www.youtube.com/watch?v=6s_B0WvJauU) by Shimomura Tomoki -- [WordPress Playground: How to use Blueprints](https://www.youtube.com/watch?v=Vcao6uXguWg) by Shimomura Tomoki -- [Streamlined Block Theme Development: Using WordPress Playground and GitHub for No-Code Version Control of Site Editor Changes](https://wordpress.tv/2025/09/30/streamlined-block-theme-development-using-wordpress-playground-and-github-for-no-code-version-contr/) by Birgit Pauli-Haack -- [Playground, la mejor herramienta jamás inventada para enseñar WordPress (in Spanish)](https://wordpress.tv/2025/10/05/playground-la-mejor-herramienta-jamas-inventada-para-ensenar-wordpress/) by Nilo Vélez -- [Testing Faster Than a Red Bull Pit Stop: WordPress Playground and WooCommerce Blueprints](https://wordpress.tv/2025/09/30/testing-faster-than-a-red-bull-pit-stop-wordpress-playground-and-woocommerce-blueprints/) by Daniel Dudzic -- [Is WordPress playground only for developers?](https://wordpress.tv/2025/10/25/is-wordpress-playground-only-for-developers/) by Fellyph Cintra -- [How to test the next WordPress release with WordPress Playground](https://wordpress.tv/2025/11/13/how-to-test-the-next-wordpress-release-with-wordpress-playground/) by Fellyph cintra -- [Running WordPress directly from the JavaScript code with runCLI](https://wordpress.tv/2025/10/22/running-wordpress-directly-from-the-javascript-code-with-runcli/) by Fellyph Cintra -- [WordPress Playground: The Path to Test Automation](https://wordpress.tv/2025/11/24/wordpress-playground-the-path-to-test-automation/) by Fellyph Cintra +- Developer Hours Videos: + - [Americas Region (May 23,2023)](https://wordpress.tv/2023/05/23/developer-hours-wordpress-playground-americas/) + - [APAC/EMEA Region (May 24,2023)](https://wordpress.tv/2023/05/24/developer-hours-wordpress-playground-apac-emea/) + - [Creating WordPress Playground Blueprints for Testing and Demos (May 28, 2024)](https://wordpress.tv/2024/05/28/developer-hours-creating-wordpress-playground-blueprints-for-testing-and-demos/) by Birgit Pauli-Haack & Nick Diego + - [Developer Hours: Everything you need to know about WordPress Playground (Dec 17, 2024)](https://wordpress.tv/2024/12/17/developer-hours-everything-you-need-to-know-about-wordpress-playground/) by Nick Diego & Ryan Welcher +- [Playground at State of the Word](https://youtu.be/VeigCZuxnfY?t=2912) +- [Playground at WCEU 2023](https://www.youtube.com/watch?v=e-CwouzTGp4&t=26946s) +- [Watch "WordPress Playground: the ultimate learning, testing, & teaching tool for WordPress"](https://www.youtube.com/watch?v=dN_LaenY8bI) by Anne McCarthy +- [WordPress Playground for developers](https://wordpress.tv/2024/12/16/wordpress-playground-for-developers/) by Berislav Grgicak and Jonathan Bossenger +- [WordPress Playground Block code editor theme support](https://wordpress.tv/2024/10/05/wordpress-playground-block-code-editor-theme-support/) by Jonathan Bossenger +- [WordPress Playground – use WordPress without a server at WCEU 2024](https://wordpress.tv/2024/07/03/wordpress-playground-use-wordpress-without-a-server/) by Adam Zielinski +- [Code, Test, Repeat: Accelerating Development with WordPress Playground at WordCamp Larissa 2024](https://wordpress.tv/2024/12/13/code-test-repeat-accelerating-development-with-wordpress-playground/) by Uros Tasic +- [Liberating data with WordPress Playground in a Browser Extension at WordCamp Netherlands 2024](https://wordpress.tv/2024/12/24/liberating-data-with-wordpress-playground-in-a-browser-extension/) by Alex Kirk +- [Beyond the Playground: WordPress as a Tool and Product Builder at WCUS 2024](https://wordpress.tv/2024/10/10/beyond-the-playground-wordpress-as-a-tool-and-product-builder/) by Dennis Snell +- [Create a demo with Playground at WC Asia 2025](https://wordpress.tv/2025/04/30/create-a-demo-with-playground/) by Birgit Pauli-Haack +- [Dissecting WordPress Playground at WordCamp Nepal 2025](https://wordpress.tv/2025/04/30/dissecting-wordpress-playground/) by Sakar Upadhyaya Khatiwada +- [Building Automated Test with WordPress Playground at WCEU 2025](https://wordpress.tv/2025/06/07/building-automated-tests-with-wordpress-playground/)by Berislav Grgicak +- [From Zero to Demo: Mastering WordPress Playground Blueprints at WCEU 2025](https://wordpress.tv/2025/06/07/from-zero-to-demo-mastering-wordpress-playground-blueprints/) by Birgit Pauli-Haack +- [Playground at WordCamp Gliwice (in Polish)](https://www.youtube.com/watch?v=AUHklF9GdL8&list=PLiCne9CeL82_hGuJOAJlsc84WxVDSH-c9&index=4) by Adam Zielinski +- [WordPress Playground at WordCamp Wrocław 2024 (in Polish)](https://wordpress.tv/2024/12/02/wordpress-playground-przelom-w-wordpressie-2/) by Adam Zielinski +- [WordPress Playground at WordCamp Gdynia 2025 (in Polish)](https://wordpress.tv/2025/04/21/wordpress-playground/) by Magdalena Paciorek +- [Discovering Playground, the demo tool(in Spanish)](https://wordpress.tv/2024/08/09/descubriendo-playground-la-herramienta-para-hacer-demos/) by Alex Cuadra +- [WordPress Playground: Complete and functional WordPress installation(in Spanish)](https://wordpress.tv/2024/02/07/wordpress-playground-instalacion-completa-y-funcional-de-wordpress/) by Fernando García Rebolledo +- [Playground: A throwaway WordPress within your browser at WordCamp Madrid 2025(in Spanish)](https://wordpress.tv/2025/03/09/playground-un-wordpress-de-usar-y-tirar-dentro-de-tu-navegador/) by Álvaro Gómez Velasco +- [Use WordPress with just a browser! WordPress Playground Tutorial: Basic usage of Playground (in Japanese)](https://www.youtube.com/watch?v=6s_B0WvJauU) by Shimomura Tomoki +- [WordPress Playground: How to use Blueprints](https://www.youtube.com/watch?v=Vcao6uXguWg) by Shimomura Tomoki +- [Streamlined Block Theme Development: Using WordPress Playground and GitHub for No-Code Version Control of Site Editor Changes](https://wordpress.tv/2025/09/30/streamlined-block-theme-development-using-wordpress-playground-and-github-for-no-code-version-contr/) by Birgit Pauli-Haack +- [Playground, la mejor herramienta jamás inventada para enseñar WordPress (in Spanish)](https://wordpress.tv/2025/10/05/playground-la-mejor-herramienta-jamas-inventada-para-ensenar-wordpress/) by Nilo Vélez +- [Testing Faster Than a Red Bull Pit Stop: WordPress Playground and WooCommerce Blueprints](https://wordpress.tv/2025/09/30/testing-faster-than-a-red-bull-pit-stop-wordpress-playground-and-woocommerce-blueprints/) by Daniel Dudzic +- [Is WordPress playground only for developers?](https://wordpress.tv/2025/10/25/is-wordpress-playground-only-for-developers/) by Fellyph Cintra +- [How to test the next WordPress release with WordPress Playground](https://wordpress.tv/2025/11/13/how-to-test-the-next-wordpress-release-with-wordpress-playground/) by Fellyph cintra +- [Running WordPress directly from the JavaScript code with runCLI](https://wordpress.tv/2025/10/22/running-wordpress-directly-from-the-javascript-code-with-runcli/) by Fellyph Cintra +- [WordPress Playground: The Path to Test Automation](https://wordpress.tv/2025/11/24/wordpress-playground-the-path-to-test-automation/) by Fellyph Cintra diff --git a/packages/docs/site/i18n/pt-BR/docusaurus-plugin-content-docs/current/main/contributor-day-table-lead.md b/packages/docs/site/i18n/pt-BR/docusaurus-plugin-content-docs/current/main/contributor-day-table-lead.md index 94b04b494e..012fccc421 100644 --- a/packages/docs/site/i18n/pt-BR/docusaurus-plugin-content-docs/current/main/contributor-day-table-lead.md +++ b/packages/docs/site/i18n/pt-BR/docusaurus-plugin-content-docs/current/main/contributor-day-table-lead.md @@ -12,10 +12,10 @@ Este guia ajuda os contribuidores a se prepararem e gerenciarem uma mesa de cont ### Lista prévia -- **Organizar "Good First Issues"**: Revise e atualize a [good first issues list](https://github.com/WordPress/wordpress-playground/labels/good%20first%20issue) no GitHub. Devem ser tarefas diretas que novos contribuidores possam completar de forma independente. Se encontrar um erro que não está na lista, mas que poderia fazer parte dela, entre em contato com a equipe do Playground no canal do Slack. -- **Coordenar com a Equipe do Playground**: Confirme se os membros da equipe do Playground estão disponíveis online para fornecer suporte remoto durante o evento, especialmente para WordCamps de grande porte. Devido a diferenças de fuso horário, alinhe-se com antecedência no canal #playground para verificar a disponibilidade. -- **Conecte com contribuidores locais**: Identifique contribuidores regulares na região que estão participando do evento. Verifique no Canal Slack #playground se um membro ativo da comunidade está participando do dia do contribuidor. Esta é uma oportunidade para coletar feedback e fortalecer as conexões comunitárias. -- **Confira o repositorio do Playground**: Se você nunca contribuiu com o repositório do WordPress Playground, você deve primeiro se familiarizar com ele. Uma seção na documentação que pode guiá-lo a entender o projeto é a [Desenvolvedores > Arquitetura](/developers/architecture). Ela conterá informações sobre como o projeto está organizado. Se tiver alguma dúvida, entre em contato com a equipe no canal Slack do Playground. +- **Organizar "Good First Issues"**: Revise e atualize a [good first issues list](https://github.com/WordPress/wordpress-playground/labels/good%20first%20issue) no GitHub. Devem ser tarefas diretas que novos contribuidores possam completar de forma independente. Se encontrar um erro que não está na lista, mas que poderia fazer parte dela, entre em contato com a equipe do Playground no canal do Slack. +- **Coordenar com a Equipe do Playground**: Confirme se os membros da equipe do Playground estão disponíveis online para fornecer suporte remoto durante o evento, especialmente para WordCamps de grande porte. Devido a diferenças de fuso horário, alinhe-se com antecedência no canal #playground para verificar a disponibilidade. +- **Conecte com contribuidores locais**: Identifique contribuidores regulares na região que estão participando do evento. Verifique no Canal Slack #playground se um membro ativo da comunidade está participando do dia do contribuidor. Esta é uma oportunidade para coletar feedback e fortalecer as conexões comunitárias. +- **Confira o repositorio do Playground**: Se você nunca contribuiu com o repositório do WordPress Playground, você deve primeiro se familiarizar com ele. Uma seção na documentação que pode guiá-lo a entender o projeto é a [Desenvolvedores > Arquitetura](/developers/architecture). Ela conterá informações sobre como o projeto está organizado. Se tiver alguma dúvida, entre em contato com a equipe no canal Slack do Playground. ## Iniciando o dia @@ -28,7 +28,6 @@ Este guia ajuda os contribuidores a se prepararem e gerenciarem uma mesa de cont 3. **Publique uma mensagem de boas-vindas**: Compartilhe uma mensagem inicial no canal Slack anunciando sua presença (pessoalmente ou online) e dando as boas-vindas às contribuições de todos. 4. **Compartilhe links essenciais**: Publique estes recursos no canal `#playground`: - - [Instância Web do WordPress Playground](https://playground.wordpress.net/) - [Documentação do Playground](https://wordpress.github.io/wordpress-playground/) - [Biblioteca de etapas](https://akirk.github.io/playground-step-library/) @@ -45,10 +44,10 @@ Este guia ajuda os contribuidores a se prepararem e gerenciarem uma mesa de cont Verifique os níveis dos contribuidores, tente entender com base no nível deles como podem contribuir para o projeto no curto período de tempo de um dia do contribuidor. Pergunte se os participantes precisam de ajuda e os redirecione para a página de documentação relacionada. Além disso, incentive-os a fazer perguntas no [Canal #playground do Slack](https://wordpress.slack.com/archives/C04EWKGDJ0K). Aqui estão algumas sugestões de formas de contribuir: -- Melhorias e traduções de documentação. -- Tíquetes cuidadosamente elaborados, descrevendo problemas com soluções acionáveis. -- Criação de Blueprints e demos de plugins no repositório de plugins do WordPress. -- Testes e feedback do produto. +- Melhorias e traduções de documentação. +- Tíquetes cuidadosamente elaborados, descrevendo problemas com soluções acionáveis. +- Criação de Blueprints e demos de plugins no repositório de plugins do WordPress. +- Testes e feedback do produto. **Fomentar a Colaboração**: Procure por oportunidades entre mesas. Por exemplo, contribuidores da [mesa de Traduções/Poliglotas ](https://make.wordpress.org/polyglots/) podem traduzir a documentação do Playground, ou a mesa do [time de testes do núcleo](https://make.wordpress.org/test/) pode fornecer feedback valioso sobre o Playground. @@ -61,7 +60,6 @@ Verifique os níveis dos contribuidores, tente entender com base no nível deles 1. **Revisar Pull Requests (PRs)**: Liste as PRs criadas durante o dia e avalie a probabilidade de serem concluídas. A maioria das contribuições tem uma janela de momentum curta, e o engajamento dentro das primeiras duas semanas é crítico. 2. **Definir expectativas claras**: Para PRs incompletas, siga esta abordagem: - - Após um mês de inatividade, deixe um comentário perguntando se o autor planeja completar o trabalho. - Se não houver resposta após mais duas semanas, informe que a PR poderá ser assumida por outro contribuidor ou fechada. @@ -71,8 +69,8 @@ Verifique os níveis dos contribuidores, tente entender com base no nível deles ## Obtendo ajuda -- **Durante o evento**: Conecte-se com contribuidores na mesa do Playground. -- **Suporte contínuo**: Use o [canal `#playground` do Slack](https://wordpress.slack.com/archives/C04EWKGDJ0K). -- **Report Issues**: Envie para o [Repositorio do WordPress Playground no GitHub](https://github.com/WordPress/wordpress-playground/issues/new). +- **Durante o evento**: Conecte-se com contribuidores na mesa do Playground. +- **Suporte contínuo**: Use o [canal `#playground` do Slack](https://wordpress.slack.com/archives/C04EWKGDJ0K). +- **Report Issues**: Envie para o [Repositorio do WordPress Playground no GitHub](https://github.com/WordPress/wordpress-playground/issues/new). Para mais informações sobre como contribuir para o WordPress Playground, consulte o [Guia do dia do contribuidor](/contributing/contributor-day). diff --git a/packages/php-wasm/cli/src/main.ts b/packages/php-wasm/cli/src/main.ts index 2f41fa94bf..95b0006c90 100644 --- a/packages/php-wasm/cli/src/main.ts +++ b/packages/php-wasm/cli/src/main.ts @@ -119,8 +119,8 @@ ${process.argv[0]} ${process.execArgv.join(' ')} ${process.argv[1]} const sysTempDir = mkdtempSync(path.join(os.tmpdir(), 'php-wasm-sys-tmp')); const php = new PHP( await loadNodeRuntime(phpVersion, { + fileLockManager: new FileLockManagerForNode(), emscriptenOptions: { - fileLockManager: new FileLockManagerForNode(), processId: 1, ENV: { ...envVariables, diff --git a/packages/php-wasm/compile/php/phpwasm-emscripten-library-file-locking-for-node.js b/packages/php-wasm/compile/php/phpwasm-emscripten-library-file-locking-for-node.js index b6a18a9e26..70e69757c3 100644 --- a/packages/php-wasm/compile/php/phpwasm-emscripten-library-file-locking-for-node.js +++ b/packages/php-wasm/compile/php/phpwasm-emscripten-library-file-locking-for-node.js @@ -37,112 +37,6 @@ 'use strict'; const LibraryForFileLocking = { - $locking: { - /* - * This is a set of possibly locked file descriptors. - * - * When a file descriptor is closed, we need to release any associated held by this process. - * Instead of trying remember and forget file descriptors as they are locked and unlocked, - * we just track file descriptors we have locked before and try an unlock when they are closed. - */ - maybeLockedFds: new Set(), - - // From: - // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - [0]: 'shared', - [1]: 'exclusive', - [2]: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath( - path, - { noent_okay: true }, - ); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath( - nodePath, - { noent_okay: true } - ); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('{{{cDefs.F_GETFL}}}'); - const emscripten_O_ACCMODE = Number('{{{ cDefs.O_ACCMODE}}}'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace('backingNode for %s: %s', vfsPath, backingPath, backingNode); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error(`Unsupported filesystem type for path ${vfsPath}`); - } - }, - - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('{{{ cDefs.O_RDONLY}}}'); - const emscripten_O_WRONLY = Number('{{{ cDefs.O_WRONLY}}}'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }, - // Place the builtin fcntl64 implementation in an object so it is left // intact even if the function is not referenced by C/C++ code. // Ref: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#javascript-limits-in-library-files @@ -152,585 +46,13 @@ const LibraryForFileLocking = { __syscall_fcntl64__deps: [ ...LibraryManager.library.__syscall_fcntl64__deps, 'builtin_fcntl64', - '$locking', ], __syscall_fcntl64__sig: LibraryManager.library.__syscall_fcntl64__sig, __syscall_fcntl64: function __syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } -#if ASYNCIFY == 2 - return Asyncify.handleAsync(async () => { -#endif - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('{{{cDefs.F_SETFL}}}'); - const emscripten_F_GETLK = Number('{{{cDefs.F_GETLK}}}'); - const emscripten_F_SETLK = Number('{{{cDefs.F_SETLK}}}'); - const emscripten_F_SETLKW = Number('{{{cDefs.F_SETLKW}}}'); - const emscripten_SEEK_SET = Number('{{{cDefs.SEEK_SET}}}'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = -#if ASYNCIFY == 2 - await Promise.resolve( -#endif - PHPLoader.fileLockManager - .findFirstConflictingByteRangeLock(nativeFilePath, { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }) -#if ASYNCIFY == 2 - ) -#endif - ; - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: - conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = ( -#if ASYNCIFY == 2 - await Promise.resolve( -#endif - PHPLoader.fileLockManager - .lockFileByteRange(nativeFilePath, rangeLock) -#if ASYNCIFY == 2 - ) -#endif - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = ( -#if ASYNCIFY == 2 - await Promise.resolve( -#endif - PHPLoader.fileLockManager - .lockFileByteRange(nativeFilePath, rangeLock) -#if ASYNCIFY == 2 - ) -#endif - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } -#if ASYNCIFY == 2 - }); -#endif + return Module['userSpace'].fcntl64(fd, cmd, varargs); }, /** @@ -741,128 +63,12 @@ const LibraryForFileLocking = { * @returns Zero on success, or a negative errno on failure. */ js_flock: function js_flock(fd, op) { -#if ASYNCIFY == 2 - return Asyncify.handleAsync(async () => { -#endif - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = ( -#if ASYNCIFY == 2 - await Promise.resolve( -#endif - PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ) -#if ASYNCIFY == 2 - ) -#endif - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace('js_flock(%d, %d) lockWholeFile error %s', fd, op, e); - return -ERRNO_CODES.EINVAL; - } -#if ASYNCIFY == 2 - }); -#endif + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); }, builtin_fd_close: LibraryManager.library.fd_close, @@ -875,64 +81,10 @@ const LibraryForFileLocking = { * @returns Zero on success, or a negative errno on failure. */ fd_close(fd) { -#if ASYNCIFY == 2 - return Asyncify.handleAsync(async () => { -#endif - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); -#if ASYNCIFY == 2 - await -#endif - PHPLoader.fileLockManager - .releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace( - 'fd_close(%d) release locks success', - fd - ); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; -#if ASYNCIFY == 2 - }); -#endif + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); }, fd_close__deps: ['builtin_fd_close', 'js_wasm_trace'], @@ -942,32 +94,10 @@ const LibraryForFileLocking = { * This function should be called at the end of each PHP request. */ js_release_file_locks: function js_release_file_locks() { -#if ASYNCIFY == 2 - return Asyncify.handleAsync(async () => { -#endif - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { -#if ASYNCIFY == 2 - await Promise.resolve( -#endif - PHPLoader.fileLockManager - .releaseLocksForProcess(pid) -#if ASYNCIFY == 2 - ) -#endif - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } -#if ASYNCIFY == 2 - }); -#endif + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); }, }; diff --git a/packages/php-wasm/compile/php/phpwasm-emscripten-library.js b/packages/php-wasm/compile/php/phpwasm-emscripten-library.js index 36d168d611..96b0220a6c 100644 --- a/packages/php-wasm/compile/php/phpwasm-emscripten-library.js +++ b/packages/php-wasm/compile/php/phpwasm-emscripten-library.js @@ -10,7 +10,7 @@ const LibraryExample = { // Emscripten dependencies: $PHPWASM__deps: ['$allocateUTF8OnStack'], - $PHPWASM__postset: 'PHPWASM.init(PHPLoader?.phpWasmInitOptions);', + $PHPWASM__postset: 'PHPWASM.init();', // Functions not exposed to C but available in the generated // JavaScript library under the PHPWASM object: @@ -28,7 +28,81 @@ const LibraryExample = { // emscripten_O_NDELAY | // emscripten_O_DIRECT | // emscripten_O_NOATIME - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('{{{cDefs.F_GETFL}}}'), + O_ACCMODE: Number('{{{cDefs.O_ACCMODE}}}'), + O_RDONLY: Number('{{{cDefs.O_RDONLY}}}'), + O_WRONLY: Number('{{{cDefs.O_WRONLY}}}'), + O_APPEND: Number('{{{cDefs.O_APPEND}}}'), + O_NONBLOCK: Number('{{{cDefs.O_NONBLOCK}}}'), + F_SETFL: Number('{{{cDefs.F_SETFL}}}'), + F_GETLK: Number('{{{cDefs.F_GETLK}}}'), + F_SETLK: Number('{{{cDefs.F_SETLK}}}'), + F_SETLKW: Number('{{{cDefs.F_SETLKW}}}'), + SEEK_SET: Number('{{{cDefs.SEEK_SET}}}'), + SEEK_CUR: Number('{{{cDefs.SEEK_CUR}}}'), + SEEK_END: Number('{{{cDefs.SEEK_END}}}'), + F_GETFL: Number('{{{cDefs.F_GETFL}}}'), + O_ACCMODE: Number('{{{cDefs.O_ACCMODE}}}'), + O_RDONLY: Number('{{{cDefs.O_RDONLY}}}'), + O_WRONLY: Number('{{{cDefs.O_WRONLY}}}'), + O_APPEND: Number('{{{cDefs.O_APPEND}}}'), + O_NONBLOCK: Number('{{{cDefs.O_NONBLOCK}}}'), + F_SETFL: Number('{{{cDefs.F_SETFL}}}'), + F_GETLK: Number('{{{cDefs.F_GETLK}}}'), + F_SETLK: Number('{{{cDefs.F_SETLK}}}'), + F_SETLKW: Number('{{{cDefs.F_SETLKW}}}'), + SEEK_SET: Number('{{{cDefs.SEEK_SET}}}'), + SEEK_CUR: Number('{{{cDefs.SEEK_CUR}}}'), + SEEK_END: Number('{{{cDefs.SEEK_END}}}'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -47,10 +121,10 @@ const LibraryExample = { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } diff --git a/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm b/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm index 55401f883f..b00a2edbe6 100755 Binary files a/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm and b/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm b/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm index fe30ecf26b..8a952b6bb2 100755 Binary files a/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm and b/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm b/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm index 894930acce..822b96cf3d 100755 Binary files a/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm and b/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm b/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm index 7d46df5ef2..ee9aca2827 100755 Binary files a/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm and b/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm b/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm index 345ca08340..c6346885bf 100755 Binary files a/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm and b/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm b/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm index 9509e9d12e..b13516a08e 100755 Binary files a/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm and b/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm b/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm index 35842443b2..1a4b34d682 100755 Binary files a/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm and b/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm b/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm index 0d57078c02..b78edbdfd5 100755 Binary files a/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm and b/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_5_0/php_8_5.wasm b/packages/php-wasm/node/asyncify/8_5_0/php_8_5.wasm index e5dc788fbb..5025d862d5 100755 Binary files a/packages/php-wasm/node/asyncify/8_5_0/php_8_5.wasm and b/packages/php-wasm/node/asyncify/8_5_0/php_8_5.wasm differ diff --git a/packages/php-wasm/node/asyncify/php_7_2.js b/packages/php-wasm/node/asyncify/php_7_2.js index d7ac963320..6559821907 100644 --- a/packages/php-wasm/node/asyncify/php_7_2.js +++ b/packages/php-wasm/node/asyncify/php_7_2.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_2_34', 'php_7_2.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22621952; +export const dependenciesTotalSize = 22621924; const phpVersionString = '7.2.34'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7018,13 +7094,6 @@ export function init(RuntimeName, PHPLoader) { }); } - if (ENVIRONMENT_IS_NODE) { - return require('child_process').spawn(command, args, { - ...options, - shell: true, - stdio: ['pipe', 'pipe', 'pipe'], - }); - } const e = new Error( 'popen(), proc_open() etc. are unsupported on this PHP instance. Call php.setSpawnHandler() ' + 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + @@ -7064,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7171,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8992,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -9001,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17206,118 +16604,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17670,19 +16962,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18682,8 +17965,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19227,8 +18513,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19346,8 +18636,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19561,8 +18855,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19643,8 +18941,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19718,8 +19020,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19835,8 +19141,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19920,8 +19230,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20028,8 +19342,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20158,8 +19476,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20304,8 +19626,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20406,8 +19732,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20507,8 +19837,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20607,8 +19941,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20621,8 +19959,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20684,8 +20026,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20739,8 +20085,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20894,8 +20244,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21015,8 +20369,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21154,8 +20512,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21257,8 +20619,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21329,8 +20695,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21432,8 +20802,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21445,8 +20818,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21703,8 +21079,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21721,8 +21099,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21739,8 +21119,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21756,8 +21138,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21781,8 +21166,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21797,8 +21184,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21831,7 +21220,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21843,8 +21232,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21865,8 +21256,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21879,8 +21272,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21914,8 +21309,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22752,15 +22151,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22794,16 +22197,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23071,10 +22479,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23118,8 +22526,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23129,8 +22541,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23186,8 +22600,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23195,8 +22613,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23209,8 +22631,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23225,8 +22651,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23283,8 +22713,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23305,8 +22740,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23327,8 +22767,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23659,16 +23104,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24621,8 +24074,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24841,15 +24298,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25010,8 +24473,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25021,8 +24488,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25037,8 +24508,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25048,8 +24523,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25113,10 +24592,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25131,10 +24613,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25163,8 +24648,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25202,8 +24692,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25259,8 +24752,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25375,8 +24871,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25536,8 +25034,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26591,15 +26092,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26631,14 +26138,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26653,14 +26164,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26677,14 +26192,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26700,14 +26220,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26864,8 +26388,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26914,8 +26441,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27926,8 +27455,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29551,9 +29083,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30011,8 +29546,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30080,8 +29617,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30816,8 +30355,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31202,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31225,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31251,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31286,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31407,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_7_3.js b/packages/php-wasm/node/asyncify/php_7_3.js index 1f517cbbbe..29d91c42f0 100644 --- a/packages/php-wasm/node/asyncify/php_7_3.js +++ b/packages/php-wasm/node/asyncify/php_7_3.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_3_33', 'php_7_3.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22663136; +export const dependenciesTotalSize = 22663154; const phpVersionString = '7.3.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17199,118 +16604,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17663,19 +16962,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18675,8 +17965,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19220,8 +18513,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19339,8 +18636,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19554,8 +18855,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19636,8 +18941,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19711,8 +19020,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19828,8 +19141,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19913,8 +19230,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20021,8 +19342,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20151,8 +19476,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20297,8 +19626,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20399,8 +19732,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20500,8 +19837,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20600,8 +19941,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20614,8 +19959,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20677,8 +20026,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20732,8 +20085,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20887,8 +20244,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21008,8 +20369,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21147,8 +20512,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21250,8 +20619,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21322,8 +20695,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21425,8 +20802,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21438,8 +20818,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21696,8 +21079,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21714,8 +21099,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21732,8 +21119,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21749,8 +21138,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21774,8 +21166,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21790,8 +21184,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21824,7 +21220,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21836,8 +21232,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21858,8 +21256,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21872,8 +21272,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21907,8 +21309,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22745,15 +22151,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22787,16 +22197,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23064,10 +22479,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23111,8 +22526,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23122,8 +22541,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23179,8 +22600,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23188,8 +22613,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23202,8 +22631,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23218,8 +22651,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23276,8 +22713,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23298,8 +22740,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23320,8 +22767,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23652,16 +23104,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24614,8 +24074,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24834,15 +24298,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25003,8 +24473,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25014,8 +24488,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25030,8 +24508,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25041,8 +24523,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25106,10 +24592,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25124,10 +24613,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25156,8 +24648,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25195,8 +24692,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25252,8 +24752,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25368,8 +24871,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25529,8 +25034,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26584,15 +26092,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26624,14 +26138,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26646,14 +26164,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26670,14 +26192,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26693,14 +26220,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26857,8 +26388,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26907,8 +26441,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27919,8 +27455,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29544,9 +29083,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30004,8 +29546,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30073,8 +29617,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30809,8 +30355,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_7_4.js b/packages/php-wasm/node/asyncify/php_7_4.js index a39b026d14..612f2385e8 100644 --- a/packages/php-wasm/node/asyncify/php_7_4.js +++ b/packages/php-wasm/node/asyncify/php_7_4.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_4_33', 'php_7_4.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22934580; +export const dependenciesTotalSize = 22934605; const phpVersionString = '7.4.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17199,118 +16604,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17663,19 +16962,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18679,8 +17969,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19224,8 +18517,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19343,8 +18640,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19558,8 +18859,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19640,8 +18945,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19715,8 +19024,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19832,8 +19145,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19917,8 +19234,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20025,8 +19346,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20155,8 +19480,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20301,8 +19630,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20403,8 +19736,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20504,8 +19841,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20604,8 +19945,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20618,8 +19963,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20681,8 +20030,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20736,8 +20089,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20891,8 +20248,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21012,8 +20373,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21151,8 +20516,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21254,8 +20623,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21326,8 +20699,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21429,8 +20806,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21442,8 +20822,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21700,8 +21083,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21718,8 +21103,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21736,8 +21123,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21753,8 +21142,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21778,8 +21170,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21794,8 +21188,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21828,7 +21224,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21840,8 +21236,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21862,8 +21260,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21876,8 +21276,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21911,8 +21313,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22749,15 +22155,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22791,16 +22201,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23068,10 +22483,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23115,8 +22530,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23126,8 +22545,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23183,8 +22604,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23192,8 +22617,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23206,8 +22635,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23222,8 +22655,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23280,8 +22717,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23302,8 +22744,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23324,8 +22771,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23656,16 +23108,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24618,8 +24078,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24838,15 +24302,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25007,8 +24477,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25018,8 +24492,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25034,8 +24512,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25045,8 +24527,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25110,10 +24596,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25128,10 +24617,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25160,8 +24652,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25199,8 +24696,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25256,8 +24756,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25372,8 +24875,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25533,8 +25038,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26588,15 +26096,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26628,14 +26142,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26650,14 +26168,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26674,14 +26196,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26697,14 +26224,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26861,8 +26392,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26911,8 +26445,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27923,8 +27459,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29548,9 +29087,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30008,8 +29550,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30077,8 +29621,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30813,8 +30359,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_0.js b/packages/php-wasm/node/asyncify/php_8_0.js index 8e6766acf9..8703f654c1 100644 --- a/packages/php-wasm/node/asyncify/php_8_0.js +++ b/packages/php-wasm/node/asyncify/php_8_0.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_0_30', 'php_8_0.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 23235004; +export const dependenciesTotalSize = 23235017; const phpVersionString = '8.0.30'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7019,7 +7095,7 @@ export function init(RuntimeName, PHPLoader) { } const e = new Error( - 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' + + 'popen(), proc_open() etc. are unsupported on this PHP instance. Call php.setSpawnHandler() ' + 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + 'and similar functions via php.ini.' ); @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17199,118 +16604,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17663,19 +16962,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18679,8 +17969,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19224,8 +18517,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19343,8 +18640,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19558,8 +18859,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19640,8 +18945,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19715,8 +19024,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19832,8 +19145,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19917,8 +19234,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20025,8 +19346,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20155,8 +19480,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20301,8 +19630,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20403,8 +19736,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20504,8 +19841,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20604,8 +19945,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20618,8 +19963,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20681,8 +20030,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20736,8 +20089,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20891,8 +20248,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21012,8 +20373,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21151,8 +20516,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21254,8 +20623,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21326,8 +20699,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21429,8 +20806,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21442,8 +20822,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21700,8 +21083,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21718,8 +21103,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21736,8 +21123,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21753,8 +21142,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21778,8 +21170,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21794,8 +21188,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21828,7 +21224,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21840,8 +21236,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21862,8 +21260,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21876,8 +21276,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21911,8 +21313,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22749,15 +22155,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22791,16 +22201,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23068,10 +22483,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23115,8 +22530,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23126,8 +22545,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23183,8 +22604,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23192,8 +22617,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23206,8 +22635,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23222,8 +22655,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23280,8 +22717,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23302,8 +22744,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23324,8 +22771,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23656,16 +23108,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24618,8 +24078,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24838,15 +24302,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25007,8 +24477,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25018,8 +24492,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25034,8 +24512,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25045,8 +24527,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25110,10 +24596,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25128,10 +24617,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25160,8 +24652,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25199,8 +24696,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25256,8 +24756,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25372,8 +24875,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25533,8 +25038,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26588,15 +26096,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26628,14 +26142,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26650,14 +26168,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26674,14 +26196,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26697,14 +26224,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26861,8 +26392,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26911,8 +26445,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27923,8 +27459,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29548,9 +29087,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30008,8 +29550,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30077,8 +29621,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30813,8 +30359,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_1.js b/packages/php-wasm/node/asyncify/php_8_1.js index 1964c6c1b1..ff426f46ea 100644 --- a/packages/php-wasm/node/asyncify/php_8_1.js +++ b/packages/php-wasm/node/asyncify/php_8_1.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_1_33', 'php_8_1.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 27231367; +export const dependenciesTotalSize = 27231372; const phpVersionString = '8.1.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17201,118 +16606,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17665,19 +16964,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18685,8 +17975,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19230,8 +18523,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19349,8 +18646,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19564,8 +18865,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19646,8 +18951,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19721,8 +19030,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19838,8 +19151,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19923,8 +19240,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20031,8 +19352,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20161,8 +19486,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20307,8 +19636,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20409,8 +19742,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20510,8 +19847,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20610,8 +19951,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20624,8 +19969,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20687,8 +20036,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20742,8 +20095,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20897,8 +20254,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21018,8 +20379,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21157,8 +20522,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21260,8 +20629,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21332,8 +20705,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21435,8 +20812,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21448,8 +20828,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21706,8 +21089,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21724,8 +21109,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21742,8 +21129,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21759,8 +21148,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21784,8 +21176,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21800,8 +21194,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21834,7 +21230,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21846,8 +21242,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21868,8 +21266,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21882,8 +21282,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21917,8 +21319,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22755,15 +22161,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22797,16 +22207,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23074,10 +22489,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23121,8 +22536,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23132,8 +22551,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23189,8 +22610,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23198,8 +22623,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23212,8 +22641,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23228,8 +22661,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23286,8 +22723,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23308,8 +22750,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23330,8 +22777,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23662,16 +23114,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24624,8 +24084,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24844,15 +24308,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25013,8 +24483,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25024,8 +24498,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25040,8 +24518,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25051,8 +24533,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25116,10 +24602,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25134,10 +24623,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25166,8 +24658,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25205,8 +24702,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25262,8 +24762,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25378,8 +24881,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25539,8 +25044,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26594,15 +26102,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26634,14 +26148,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26656,14 +26174,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26680,14 +26202,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26703,14 +26230,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26867,8 +26398,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26917,8 +26451,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27929,8 +27465,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29554,9 +29093,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30014,8 +29556,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30083,8 +29627,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30819,8 +30365,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_2.js b/packages/php-wasm/node/asyncify/php_8_2.js index c08e2bd5df..bfab213e3a 100644 --- a/packages/php-wasm/node/asyncify/php_8_2.js +++ b/packages/php-wasm/node/asyncify/php_8_2.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_2_29', 'php_8_2.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 27519844; +export const dependenciesTotalSize = 27519848; const phpVersionString = '8.2.29'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17203,118 +16608,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17667,19 +16966,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18687,8 +17977,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19232,8 +18525,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19351,8 +18648,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19566,8 +18867,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19648,8 +18953,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19723,8 +19032,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19840,8 +19153,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19925,8 +19242,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20033,8 +19354,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20163,8 +19488,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20309,8 +19638,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20411,8 +19744,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20512,8 +19849,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20612,8 +19953,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20626,8 +19971,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20689,8 +20038,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20744,8 +20097,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20899,8 +20256,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21020,8 +20381,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21159,8 +20524,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21262,8 +20631,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21334,8 +20707,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21437,8 +20814,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21450,8 +20830,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21708,8 +21091,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21726,8 +21111,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21744,8 +21131,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21761,8 +21150,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21786,8 +21178,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21802,8 +21196,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21836,7 +21232,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21848,8 +21244,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21870,8 +21268,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21884,8 +21284,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21919,8 +21321,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22757,15 +22163,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22799,16 +22209,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23076,10 +22491,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23123,8 +22538,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23134,8 +22553,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23191,8 +22612,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23200,8 +22625,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23214,8 +22643,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23230,8 +22663,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23288,8 +22725,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23310,8 +22752,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23332,8 +22779,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23664,16 +23116,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24626,8 +24086,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24846,15 +24310,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25015,8 +24485,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25026,8 +24500,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25042,8 +24520,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25053,8 +24535,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25118,10 +24604,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25136,10 +24625,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25168,8 +24660,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25207,8 +24704,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25264,8 +24764,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25380,8 +24883,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25541,8 +25046,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26596,15 +26104,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26636,14 +26150,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26658,14 +26176,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26682,14 +26204,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26705,14 +26232,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26869,8 +26400,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26919,8 +26453,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27931,8 +27467,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29556,9 +29095,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30016,8 +29558,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30085,8 +29629,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30821,8 +30367,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_3.js b/packages/php-wasm/node/asyncify/php_8_3.js index e55eef3048..c8b118037c 100644 --- a/packages/php-wasm/node/asyncify/php_8_3.js +++ b/packages/php-wasm/node/asyncify/php_8_3.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_3_28', 'php_8_3.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 27938593; +export const dependenciesTotalSize = 27938578; const phpVersionString = '8.3.28'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17203,118 +16608,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17667,19 +16966,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18687,8 +17977,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19232,8 +18525,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19351,8 +18648,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19566,8 +18867,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19648,8 +18953,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19723,8 +19032,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19840,8 +19153,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19925,8 +19242,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20033,8 +19354,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20163,8 +19488,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20309,8 +19638,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20411,8 +19744,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20512,8 +19849,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20612,8 +19953,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20626,8 +19971,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20689,8 +20038,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20744,8 +20097,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20899,8 +20256,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21020,8 +20381,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21159,8 +20524,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21262,8 +20631,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21334,8 +20707,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21437,8 +20814,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21450,8 +20830,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21708,8 +21091,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21726,8 +21111,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21744,8 +21131,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21761,8 +21150,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21786,8 +21178,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21802,8 +21196,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21836,7 +21232,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21848,8 +21244,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21870,8 +21268,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21884,8 +21284,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21919,8 +21321,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22757,15 +22163,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22799,16 +22209,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23076,10 +22491,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23123,8 +22538,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23134,8 +22553,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23191,8 +22612,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23200,8 +22625,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23214,8 +22643,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23230,8 +22663,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23288,8 +22725,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23310,8 +22752,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23332,8 +22779,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23664,16 +23116,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24626,8 +24086,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24846,15 +24310,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25015,8 +24485,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25026,8 +24500,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25042,8 +24520,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25053,8 +24535,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25118,10 +24604,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25136,10 +24625,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25168,8 +24660,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25207,8 +24704,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25264,8 +24764,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25380,8 +24883,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25541,8 +25046,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26596,15 +26104,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26636,14 +26150,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26658,14 +26176,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26682,14 +26204,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26705,14 +26232,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26869,8 +26400,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26919,8 +26453,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27931,8 +27467,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29556,9 +29095,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30016,8 +29558,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30085,8 +29629,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30821,8 +30367,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_4.js b/packages/php-wasm/node/asyncify/php_8_4.js index 03333e63d9..fb83e11b51 100644 --- a/packages/php-wasm/node/asyncify/php_8_4.js +++ b/packages/php-wasm/node/asyncify/php_8_4.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_4_15', 'php_8_4.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 29855641; +export const dependenciesTotalSize = 29855653; const phpVersionString = '8.4.15'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17203,118 +16608,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17667,19 +16966,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18687,8 +17977,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19232,8 +18525,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19351,8 +18648,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19566,8 +18867,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19648,8 +18953,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19723,8 +19032,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19840,8 +19153,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19925,8 +19242,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20033,8 +19354,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20163,8 +19488,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20309,8 +19638,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20411,8 +19744,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20512,8 +19849,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20612,8 +19953,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20626,8 +19971,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20689,8 +20038,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20744,8 +20097,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20899,8 +20256,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21020,8 +20381,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21159,8 +20524,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21262,8 +20631,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21334,8 +20707,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21437,8 +20814,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21450,8 +20830,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21708,8 +21091,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21726,8 +21111,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21744,8 +21131,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21761,8 +21150,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21786,8 +21178,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21802,8 +21196,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21836,7 +21232,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21848,8 +21244,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21870,8 +21268,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21884,8 +21284,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21919,8 +21321,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22757,15 +22163,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22799,16 +22209,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23076,10 +22491,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23123,8 +22538,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23134,8 +22553,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23191,8 +22612,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23200,8 +22625,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23214,8 +22643,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23230,8 +22663,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23288,8 +22725,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23310,8 +22752,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23332,8 +22779,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23664,16 +23116,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24626,8 +24086,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24846,15 +24310,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25015,8 +24485,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25026,8 +24500,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25042,8 +24520,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25053,8 +24535,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25118,10 +24604,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25136,10 +24625,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25168,8 +24660,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25207,8 +24704,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25264,8 +24764,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25380,8 +24883,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25541,8 +25046,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26596,15 +26104,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26636,14 +26150,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26658,14 +26176,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26682,14 +26204,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26705,14 +26232,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26869,8 +26400,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26919,8 +26453,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27931,8 +27467,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29556,9 +29095,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30016,8 +29558,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30085,8 +29629,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30821,8 +30367,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/asyncify/php_8_5.js b/packages/php-wasm/node/asyncify/php_8_5.js index e76efe1446..0fb817bb9a 100644 --- a/packages/php-wasm/node/asyncify/php_8_5.js +++ b/packages/php-wasm/node/asyncify/php_8_5.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_5_0', 'php_8_5.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 31303379; +export const dependenciesTotalSize = 31303376; const phpVersionString = '8.5.0'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -5118,8 +5118,10 @@ export function init(RuntimeName, PHPLoader) { ); var ___call_sighandler = (fp, sig) => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ sig + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + sig ); ___call_sighandler.sig = 'vpi'; @@ -6714,7 +6716,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6733,10 +6809,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -7019,7 +7095,7 @@ export function init(RuntimeName, PHPLoader) { } const e = new Error( - 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' + + 'popen(), proc_open() etc. are unsupported on this PHP instance. Call php.setSpawnHandler() ' + 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + 'and similar functions via php.ini.' ); @@ -7057,51 +7133,10 @@ export function init(RuntimeName, PHPLoader) { } function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; + return Module['userSpace'].fd_close(fd); } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { @@ -7164,647 +7199,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -8985,8 +8384,11 @@ export function init(RuntimeName, PHPLoader) { dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -8994,8 +8396,11 @@ export function init(RuntimeName, PHPLoader) { function successCallback() { runtimeKeepalivePop(); callUserCallback(() => - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, user_data ) ); @@ -17203,118 +16608,12 @@ export function init(RuntimeName, PHPLoader) { _getprotobynumber.sig = 'pi'; function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. return 0; } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } + return Module['userSpace'].flock(fd, op); } function _js_open_process( @@ -17667,19 +16966,10 @@ export function init(RuntimeName, PHPLoader) { } function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); + if (typeof Module['userSpace'] === 'undefined') { + return; } + return Module['userSpace'].js_release_file_locks(); } function _js_waitpid(pid, exitCodePtr) { @@ -18687,8 +17977,11 @@ export function init(RuntimeName, PHPLoader) { var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { - var ret = ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0, + var ret = (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0, arg ); if (ret !== 0) return; @@ -19232,8 +18525,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(e.locale || '', keyEventData + 128, 32); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, keyEventData, userData ) @@ -19351,8 +18648,12 @@ export function init(RuntimeName, PHPLoader) { fillMouseEventData(JSEvents.mouseEvent, e, target); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.mouseEvent, userData ) @@ -19566,8 +18867,12 @@ export function init(RuntimeName, PHPLoader) { HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, wheelEvent, userData ) @@ -19648,8 +18953,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, uiEvent, userData ) @@ -19723,8 +19032,12 @@ export function init(RuntimeName, PHPLoader) { stringToUTF8(id, focusEvent + 128, 128); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, focusEvent, userData ) @@ -19840,8 +19153,12 @@ export function init(RuntimeName, PHPLoader) { ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceOrientationEvent, userData ) @@ -19925,8 +19242,12 @@ export function init(RuntimeName, PHPLoader) { fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, JSEvents.deviceMotionEvent, userData ) @@ -20033,8 +19354,12 @@ export function init(RuntimeName, PHPLoader) { fillOrientationChangeEventData(orientationChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, orientationChangeEvent, userData ) @@ -20163,8 +19488,12 @@ export function init(RuntimeName, PHPLoader) { fillFullscreenChangeEventData(fullscreenChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, fullscreenChangeEvent, userData ) @@ -20309,8 +19638,12 @@ export function init(RuntimeName, PHPLoader) { ); if (currentFullscreenStrategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20411,8 +19744,12 @@ export function init(RuntimeName, PHPLoader) { currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20512,8 +19849,12 @@ export function init(RuntimeName, PHPLoader) { !inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback ) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData ); @@ -20612,8 +19953,12 @@ export function init(RuntimeName, PHPLoader) { softFullscreenResizeWebGLRenderTarget ); if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20626,8 +19971,12 @@ export function init(RuntimeName, PHPLoader) { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 37, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 37, 0, strategy.canvasResizedCallbackUserData ); @@ -20689,8 +20038,12 @@ export function init(RuntimeName, PHPLoader) { fillPointerlockChangeEventData(pointerlockChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, pointerlockChangeEvent, userData ) @@ -20744,8 +20097,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var pointerlockErrorEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -20899,8 +20256,12 @@ export function init(RuntimeName, PHPLoader) { fillVisibilityChangeEventData(visibilityChangeEvent); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, visibilityChangeEvent, userData ) @@ -21020,8 +20381,12 @@ export function init(RuntimeName, PHPLoader) { HEAP32[(touchEvent + 8) >> 2] = numTouches; if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, touchEvent, userData ) @@ -21159,8 +20524,12 @@ export function init(RuntimeName, PHPLoader) { fillGamepadEventData(gamepadEvent, e['gamepad']); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, gamepadEvent, userData ) @@ -21262,8 +20631,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var beforeUnloadEventHandlerFunc = (e = event) => { // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + var confirmationMessage = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ); @@ -21334,8 +20707,12 @@ export function init(RuntimeName, PHPLoader) { fillBatteryEventData(batteryEvent, battery); if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, batteryEvent, userData ) @@ -21437,8 +20814,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame = (cb, userData) => requestAnimationFrame((timeStamp) => - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ); @@ -21450,8 +20830,11 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_request_animation_frame_loop = (cb, userData) => { function tick(timeStamp) { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ timeStamp, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + timeStamp, userData ) ) { @@ -21708,8 +21091,10 @@ export function init(RuntimeName, PHPLoader) { return emSetImmediate(() => { runtimeKeepalivePop(); callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }); @@ -21726,8 +21111,10 @@ export function init(RuntimeName, PHPLoader) { function tick() { callUserCallback(() => { if ( - ((a1) => {})( - /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ) { emSetImmediate(tick); @@ -21744,8 +21131,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_timeout = (cb, msecs, userData) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ), msecs ); @@ -21761,8 +21150,11 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => { if ( - ((a1, a2) => {})( - /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ t, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + t, userData ) ) { @@ -21786,8 +21178,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePush(); return setInterval(() => { callUserCallback(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ) ); }, msecs); @@ -21802,8 +21196,10 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_async_call = (func, arg, millis) => { var wrapper = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); if ( @@ -21836,7 +21232,7 @@ export function init(RuntimeName, PHPLoader) { var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { var iterFunc = - () => {}; /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ + () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; setMainLoop(iterFunc, fps, simulateInfiniteLoop); }; _emscripten_set_main_loop.sig = 'vpii'; @@ -21848,8 +21244,10 @@ export function init(RuntimeName, PHPLoader) { simulateInfiniteLoop ) => { var iterFunc = () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); }; @@ -21870,8 +21268,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21884,8 +21284,10 @@ export function init(RuntimeName, PHPLoader) { var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { MainLoop.queue.push({ func: () => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, name: UTF8ToString(name), @@ -21919,8 +21321,12 @@ export function init(RuntimeName, PHPLoader) { var resultPtr = stackAlloc(POINTER_SIZE); HEAPU32[resultPtr >> 2] = 0; try { - var result = ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ resultPtr, + var result = (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + resultPtr, userData, value ); @@ -22757,15 +22163,19 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ file + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + file ); }, true // don'tCreateFile - it's already there @@ -22799,16 +22209,21 @@ export function init(RuntimeName, PHPLoader) { () => { runtimeKeepalivePop(); if (onload) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, cname ); }, () => { runtimeKeepalivePop(); if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }, true // don'tCreateFile - it's already there @@ -23076,10 +22491,10 @@ export function init(RuntimeName, PHPLoader) { runtimeKeepalivePop(); callUserCallback(() => withStackSave(() => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stringToUTF8OnStack( - _file - ) + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stringToUTF8OnStack(_file) ) ) ); @@ -23123,8 +22538,12 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata, buffer, byteArray.length ); @@ -23134,8 +22553,10 @@ export function init(RuntimeName, PHPLoader) { if (onerror) { runtimeKeepalivePop(); callUserCallback(() => { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userdata + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userdata ); }); } @@ -23191,8 +22612,12 @@ export function init(RuntimeName, PHPLoader) { ); if (onload) { var sp = stackSave(); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, stringToUTF8OnStack(_file) ); @@ -23200,8 +22625,12 @@ export function init(RuntimeName, PHPLoader) { } } else { if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23214,8 +22643,12 @@ export function init(RuntimeName, PHPLoader) { http.onerror = (e) => { runtimeKeepalivePop(); if (onerror) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status ); @@ -23230,8 +22663,12 @@ export function init(RuntimeName, PHPLoader) { ) { var percentComplete = (e.loaded / e.total) * 100; if (onprogress) - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, percentComplete ); @@ -23288,8 +22725,13 @@ export function init(RuntimeName, PHPLoader) { if (http.statusText) { statusText = stringToUTF8OnStack(http.statusText); } - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, http.status, statusText @@ -23310,8 +22752,13 @@ export function init(RuntimeName, PHPLoader) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); if (onload) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, buffer, byteArray.length @@ -23332,8 +22779,13 @@ export function init(RuntimeName, PHPLoader) { // PROGRESS http.onprogress = (e) => { if (onprogress) - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ handle, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined @@ -23664,16 +23116,24 @@ export function init(RuntimeName, PHPLoader) { if (event === 'error') { withStackSave(() => { var msg = stringToUTF8OnStack(data[2]); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data[0], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data[0], data[1], msg, userData ); }); } else { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ data, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + data, userData ); } @@ -24626,8 +24086,12 @@ export function init(RuntimeName, PHPLoader) { ) => { var webGlEventHandlerFunc = (e = event) => { if ( - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ eventTypeId, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + eventTypeId, 0, userData ) @@ -24846,15 +24310,21 @@ export function init(RuntimeName, PHPLoader) { ) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ lastX, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + lastX, lastY ); } @@ -25015,8 +24485,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25026,8 +24500,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25042,8 +24520,12 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.specialUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25053,8 +24535,12 @@ export function init(RuntimeName, PHPLoader) { if (key !== null && GLUT.keyboardUpFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ key, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + key, Browser.mouseX, Browser.mouseY ); @@ -25118,10 +24604,13 @@ export function init(RuntimeName, PHPLoader) { } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25136,10 +24625,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ event[ - 'button' - ], + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + event['button'], 1 /*GLUT_UP*/, Browser.mouseX, Browser.mouseY @@ -25168,8 +24660,13 @@ export function init(RuntimeName, PHPLoader) { if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); - ((a1, a2, a3, a4) => {})( - /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ button, + (( + a1, + a2, + a3, + a4 + ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + button, 0 /*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY @@ -25207,8 +24704,11 @@ export function init(RuntimeName, PHPLoader) { /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ if (GLUT.reshapeFunc) { // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25264,8 +24764,11 @@ export function init(RuntimeName, PHPLoader) { // Resize callback stage 2: updateResizeListeners notifies reshapeFunc Browser.resizeListeners.push((width, height) => { if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -25380,8 +24883,10 @@ export function init(RuntimeName, PHPLoader) { var _glutTimerFunc = (msec, func, value) => safeSetTimeout( () => - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ value + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + value ), msec ); @@ -25541,8 +25046,11 @@ export function init(RuntimeName, PHPLoader) { Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. // Just call it once here. if (GLUT.reshapeFunc) { - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ width, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + width, height ); } @@ -26596,15 +26104,21 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, buffer, byteArray.length ); @@ -26636,14 +26150,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onstore) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); } @@ -26658,14 +26176,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (ondelete) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26682,14 +26204,19 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (oncheck) - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg, exists ); }); @@ -26705,14 +26232,18 @@ export function init(RuntimeName, PHPLoader) { callUserCallback(() => { if (error) { if (onerror) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); return; } if (onclear) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ arg + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + arg ); }); }); @@ -26869,8 +26400,11 @@ export function init(RuntimeName, PHPLoader) { safeSetTimeout(() => { var stackBegin = Asyncify.currData + 12; var stackEnd = HEAPU32[Asyncify.currData >> 2]; - ((a1, a2) => {})( - /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ stackBegin, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + stackBegin, stackEnd ); wakeUp(); @@ -26919,8 +26453,10 @@ export function init(RuntimeName, PHPLoader) { HEAPU32[(newFiber + 12) >> 2] = 0; var userData = HEAPU32[(newFiber + 16) >> 2]; - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ userData + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + userData ); } else { var asyncifyData = newFiber + 20; @@ -27931,8 +27467,11 @@ export function init(RuntimeName, PHPLoader) { if (!SDL.eventHandler) return; while (SDL.pollEvent(SDL.eventHandlerTemp)) { - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL.eventHandlerContext, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.eventHandlerContext, SDL.eventHandlerTemp ); } @@ -29556,9 +29095,12 @@ export function init(RuntimeName, PHPLoader) { return; // Ask SDL audio data from the user code. - ((a1, a2, a3) => {})( - /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ SDL - .audio.userdata, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize ); @@ -30016,8 +29558,10 @@ export function init(RuntimeName, PHPLoader) { info.audio = null; } if (SDL.channelFinished) { - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); } } @@ -30085,8 +29629,10 @@ export function init(RuntimeName, PHPLoader) { channelInfo.audio = null; } if (SDL.channelFinished) - ((a1) => {})( - /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ channel + (( + a1 + ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + channel ); }; if (channelInfo.audio) { @@ -30821,8 +30367,11 @@ export function init(RuntimeName, PHPLoader) { var _SDL_AddTimer = (interval, callback, param) => safeSetTimeout( () => - ((a1, a2) => {})( - /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ interval, + (( + a1, + a2 + ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + interval, param ), interval @@ -31195,8 +30744,12 @@ export function init(RuntimeName, PHPLoader) { socket.onopen = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31218,8 +30771,12 @@ export function init(RuntimeName, PHPLoader) { socket.onerror = function (e) { var eventPtr = WS.getSocketEvent(socketId); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31244,8 +30801,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAP8[eventPtr + 4] = e.wasClean), (HEAP16[(eventPtr + 6) >> 1] = e.code), stringToUTF8(e.reason, eventPtr + 8, 512)); - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData ); @@ -31279,8 +30840,12 @@ export function init(RuntimeName, PHPLoader) { ((HEAPU32[(eventPtr + 4) >> 2] = buf), (HEAP32[(eventPtr + 8) >> 2] = len), (HEAP8[eventPtr + 12] = isText), - ((a1, a2, a3) => {})( - /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ 0 /*TODO*/, + (( + a1, + a2, + a3 + ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( + 0 /*TODO*/, eventPtr, userData )); @@ -31400,7 +30965,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/7_2_34/php_7_2.wasm b/packages/php-wasm/node/jspi/7_2_34/php_7_2.wasm index 69fe9d13fa..b5867cc4dd 100755 Binary files a/packages/php-wasm/node/jspi/7_2_34/php_7_2.wasm and b/packages/php-wasm/node/jspi/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/node/jspi/7_3_33/php_7_3.wasm b/packages/php-wasm/node/jspi/7_3_33/php_7_3.wasm index 5add1f65e6..7a089cf866 100755 Binary files a/packages/php-wasm/node/jspi/7_3_33/php_7_3.wasm and b/packages/php-wasm/node/jspi/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/node/jspi/7_4_33/php_7_4.wasm b/packages/php-wasm/node/jspi/7_4_33/php_7_4.wasm index 7d215dcb11..bf883e87d7 100755 Binary files a/packages/php-wasm/node/jspi/7_4_33/php_7_4.wasm and b/packages/php-wasm/node/jspi/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/node/jspi/8_0_30/php_8_0.wasm b/packages/php-wasm/node/jspi/8_0_30/php_8_0.wasm index 8e9a95565f..5506bc3596 100755 Binary files a/packages/php-wasm/node/jspi/8_0_30/php_8_0.wasm and b/packages/php-wasm/node/jspi/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/node/jspi/8_1_33/php_8_1.wasm b/packages/php-wasm/node/jspi/8_1_33/php_8_1.wasm index b793b020c3..2712c59a56 100755 Binary files a/packages/php-wasm/node/jspi/8_1_33/php_8_1.wasm and b/packages/php-wasm/node/jspi/8_1_33/php_8_1.wasm differ diff --git a/packages/php-wasm/node/jspi/8_2_29/php_8_2.wasm b/packages/php-wasm/node/jspi/8_2_29/php_8_2.wasm index 032eb03caa..a77513646e 100755 Binary files a/packages/php-wasm/node/jspi/8_2_29/php_8_2.wasm and b/packages/php-wasm/node/jspi/8_2_29/php_8_2.wasm differ diff --git a/packages/php-wasm/node/jspi/8_3_28/php_8_3.wasm b/packages/php-wasm/node/jspi/8_3_28/php_8_3.wasm index 9798477503..eccfbed05f 100755 Binary files a/packages/php-wasm/node/jspi/8_3_28/php_8_3.wasm and b/packages/php-wasm/node/jspi/8_3_28/php_8_3.wasm differ diff --git a/packages/php-wasm/node/jspi/8_4_15/php_8_4.wasm b/packages/php-wasm/node/jspi/8_4_15/php_8_4.wasm index bfdb4a2a28..7d0dd3befa 100755 Binary files a/packages/php-wasm/node/jspi/8_4_15/php_8_4.wasm and b/packages/php-wasm/node/jspi/8_4_15/php_8_4.wasm differ diff --git a/packages/php-wasm/node/jspi/8_5_0/php_8_5.wasm b/packages/php-wasm/node/jspi/8_5_0/php_8_5.wasm index 1a0733afc8..59a1e93e6f 100755 Binary files a/packages/php-wasm/node/jspi/8_5_0/php_8_5.wasm and b/packages/php-wasm/node/jspi/8_5_0/php_8_5.wasm differ diff --git a/packages/php-wasm/node/jspi/php_7_2.js b/packages/php-wasm/node/jspi/php_7_2.js index 82d0c0a821..6a533f93b5 100644 --- a/packages/php-wasm/node/jspi/php_7_2.js +++ b/packages/php-wasm/node/jspi/php_7_2.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_2_34', 'php_7_2.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22140853; +export const dependenciesTotalSize = 22140824; const phpVersionString = '7.2.34'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17048,122 +16427,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17514,27 +16785,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_7_3.js b/packages/php-wasm/node/jspi/php_7_3.js index 28467ef87d..8dc84d7176 100644 --- a/packages/php-wasm/node/jspi/php_7_3.js +++ b/packages/php-wasm/node/jspi/php_7_3.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_3_33', 'php_7_3.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22198114; +export const dependenciesTotalSize = 22198121; const phpVersionString = '7.3.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17048,122 +16427,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17514,27 +16785,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_7_4.js b/packages/php-wasm/node/jspi/php_7_4.js index 2a44ca86e9..359999736a 100644 --- a/packages/php-wasm/node/jspi/php_7_4.js +++ b/packages/php-wasm/node/jspi/php_7_4.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '7_4_33', 'php_7_4.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22427163; +export const dependenciesTotalSize = 22427217; const phpVersionString = '7.4.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17048,122 +16427,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17514,27 +16785,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_0.js b/packages/php-wasm/node/jspi/php_8_0.js index de933cdb24..ac1b7fc870 100644 --- a/packages/php-wasm/node/jspi/php_8_0.js +++ b/packages/php-wasm/node/jspi/php_8_0.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_0_30', 'php_8_0.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 22718385; +export const dependenciesTotalSize = 22718381; const phpVersionString = '8.0.30'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17048,122 +16427,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17514,27 +16785,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_1.js b/packages/php-wasm/node/jspi/php_8_1.js index 93925dfec5..addc1fd191 100644 --- a/packages/php-wasm/node/jspi/php_8_1.js +++ b/packages/php-wasm/node/jspi/php_8_1.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_1_33', 'php_8_1.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 26663652; +export const dependenciesTotalSize = 26663657; const phpVersionString = '8.1.33'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17050,122 +16429,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17516,27 +16787,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_2.js b/packages/php-wasm/node/jspi/php_8_2.js index 5cbb2f9615..d4056a9887 100644 --- a/packages/php-wasm/node/jspi/php_8_2.js +++ b/packages/php-wasm/node/jspi/php_8_2.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_2_29', 'php_8_2.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 26936075; +export const dependenciesTotalSize = 26936079; const phpVersionString = '8.2.29'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17052,122 +16431,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17518,27 +16789,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_3.js b/packages/php-wasm/node/jspi/php_8_3.js index 435f53077d..94342b4735 100644 --- a/packages/php-wasm/node/jspi/php_8_3.js +++ b/packages/php-wasm/node/jspi/php_8_3.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17052,122 +16431,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17518,27 +16789,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_4.js b/packages/php-wasm/node/jspi/php_8_4.js index 17235b26cb..956e9a8be7 100644 --- a/packages/php-wasm/node/jspi/php_8_4.js +++ b/packages/php-wasm/node/jspi/php_8_4.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_4_15', 'php_8_4.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 29263184; +export const dependenciesTotalSize = 29263167; const phpVersionString = '8.4.15'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17052,122 +16431,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17518,27 +16789,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/jspi/php_8_5.js b/packages/php-wasm/node/jspi/php_8_5.js index bcc0e52053..6042c4cf22 100644 --- a/packages/php-wasm/node/jspi/php_8_5.js +++ b/packages/php-wasm/node/jspi/php_8_5.js @@ -8,7 +8,7 @@ import path from 'path'; const dependencyFilename = path.join(__dirname, '8_5_0', 'php_8_5.wasm'); export { dependencyFilename }; -export const dependenciesTotalSize = 30716158; +export const dependenciesTotalSize = 30716170; const phpVersionString = '8.5.0'; export function init(RuntimeName, PHPLoader) { // The rest of the code comes from the built php.js file and esm-suffix.js @@ -6557,7 +6557,81 @@ export function init(RuntimeName, PHPLoader) { O_NONBLOCK: 2048, POLLHUP: 16, SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { + init: function () { + // TODO: Move this to a library function that is made an onInit callback by the `__postset` suffix. + if (PHPLoader.bindUserSpace) { + /** + * We need to add an onInit callback to bind the user-space API + * because some dependencies like wasmImports and wasmExports + * are not yet assigned. + */ + addOnInit(() => { + Module['userSpace'] = PHPLoader.bindUserSpace({ + // TODO: Require PID instead of defaulting to 42. + pid: PHPLoader.processId ?? 42, + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + F_GETFL: Number('3'), + O_ACCMODE: Number('2097155'), + O_RDONLY: Number('0'), + O_WRONLY: Number('1'), + O_APPEND: Number('1024'), + O_NONBLOCK: Number('2048'), + F_SETFL: Number('4'), + F_GETLK: Number('12'), + F_SETLK: Number('13'), + F_SETLKW: Number('14'), + SEEK_SET: Number('0'), + SEEK_CUR: Number('1'), + SEEK_END: Number('2'), + // From: + // https://github.com/emscripten-core/emscripten/blob/66d2137b0381ac35f7e2346b2d6a90abd0f1211a/system/lib/libc/musl/include/fcntl.h#L58-L60 + F_RDLCK: 0, + F_WRLCK: 1, + F_UNLCK: 2, + // From: + // https://github.com/emscripten-core/emscripten/blob/81bbaa42a7827d88a71bd89701245052c622428c/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1, + LOCK_EX: 2, + LOCK_NB: 4, // Non-blocking lock + LOCK_UN: 8, // Unlock + }, + errnoCodes: ERRNO_CODES, + memory: { + HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64, + }, + wasmImports, + wasmExports, + syscalls: SYSCALLS, + FS, + PROXYFS, + NODEFS, + }); + }); + } + Module['ENV'] = Module['ENV'] || {}; // Ensure a platform-level bin directory for a fallback `php` binary. Module['ENV']['PATH'] = [ @@ -6576,10 +6650,10 @@ export function init(RuntimeName, PHPLoader) { // and contains the php.ini, constants definitions, etc. FS.mkdir('/internal'); - if (phpWasmInitOptions?.nativeInternalDirPath) { + if (PHPLoader.nativeInternalDirPath) { FS.mount( FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, + { root: PHPLoader.nativeInternalDirPath }, '/internal' ); } @@ -6899,55 +6973,12 @@ export function init(RuntimeName, PHPLoader) { } } - var _fd_close = function fd_close(fd) { - return Asyncify.handleAsync(async () => { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - await PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - }); - }; + function _fd_close(fd) { + if (typeof Module['userSpace'] === 'undefined') { + return _builtin_fd_close(fd); + } + return Module['userSpace'].fd_close(fd); + } _fd_close.sig = 'ii'; function _builtin_fd_close(fd) { try { @@ -7009,663 +7040,11 @@ export function init(RuntimeName, PHPLoader) { } } - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (!node) { - return false; - } - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { + if (typeof Module['userSpace'] === 'undefined') { return _builtin_fcntl64(fd, cmd, varargs); } - return Asyncify.handleAsync(async () => { - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> - 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> - 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> - 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = await Promise.resolve( - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: - absoluteStartOffset + flockStruct.l_len, - pid, - } - ) - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement a blocking version of F_SETLKW instead of - // treating it the same as F_SETLK. - case emscripten_F_SETLKW: { - // F_SETLKW is the blocking version of F_SETLK. - // For now, we treat it the same as F_SETLK (non-blocking). - // In a true blocking implementation, this would wait for the lock to become available. - _js_wasm_trace('fcntl(%d, F_SETLKW)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = await Promise.resolve( - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ) - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLKW) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - }); + return Module['userSpace'].fcntl64(fd, cmd, varargs); } ___syscall_fcntl64.sig = 'iiip'; @@ -17052,122 +16431,14 @@ export function init(RuntimeName, PHPLoader) { }; _getprotobynumber.sig = 'pi'; - var _js_flock = function js_flock(fd, op) { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & - (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = await Promise.resolve( - PHPLoader.fileLockManager.lockWholeFile(nativeFilePath, { - type: lockOpType, - pid: PHPLoader.processId, - fd, - }) - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - }); - }; + function _js_flock(fd, op) { + if (typeof Module['userSpace'] === 'undefined') { + // In the absence of a real locking facility, + // return success by default as Emscripten does. + return 0; + } + return Module['userSpace'].flock(fd, op); + } function _js_open_process( command, @@ -17518,27 +16789,12 @@ export function init(RuntimeName, PHPLoader) { return 0; } - var _js_release_file_locks = function js_release_file_locks() { - return Asyncify.handleAsync(async () => { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace( - 'js_release_file_locks no pid or file lock manager' - ); - return 0; - } - - try { - await Promise.resolve( - PHPLoader.fileLockManager.releaseLocksForProcess(pid) - ); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - }); - }; + function _js_release_file_locks() { + if (typeof Module['userSpace'] === 'undefined') { + return; + } + return Module['userSpace'].js_release_file_locks(); + } function _js_waitpid(pid, exitCodePtr) { if (!PHPWASM.processTable[pid]) { @@ -30850,7 +30106,7 @@ export function init(RuntimeName, PHPLoader) { if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); } - PHPWASM.init(PHPLoader?.phpWasmInitOptions); + PHPWASM.init(); Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; Module['pauseMainLoop'] = MainLoop.pause; diff --git a/packages/php-wasm/node/src/lib/file-lock-manager-for-node.ts b/packages/php-wasm/node/src/lib/file-lock-manager-for-node.ts index 0a740dba59..a242b0d51a 100644 --- a/packages/php-wasm/node/src/lib/file-lock-manager-for-node.ts +++ b/packages/php-wasm/node/src/lib/file-lock-manager-for-node.ts @@ -13,7 +13,7 @@ import type { WholeFileLockOp, Pid, Fd, -} from './file-lock-manager'; +} from '@php-wasm/universal'; type LockMode = 'exclusive' | 'shared' | 'unlock'; diff --git a/packages/php-wasm/node/src/lib/index.ts b/packages/php-wasm/node/src/lib/index.ts index e27461ff33..0cc3d1ed89 100644 --- a/packages/php-wasm/node/src/lib/index.ts +++ b/packages/php-wasm/node/src/lib/index.ts @@ -3,6 +3,5 @@ export * from './networking/with-networking'; export * from './load-runtime'; export * from './use-host-filesystem'; export * from './node-fs-mount'; -export * from './file-lock-manager'; export * from './file-lock-manager-for-node'; export * from './xdebug/with-xdebug'; diff --git a/packages/php-wasm/node/src/lib/load-runtime.ts b/packages/php-wasm/node/src/lib/load-runtime.ts index b7db4273d4..9323450080 100644 --- a/packages/php-wasm/node/src/lib/load-runtime.ts +++ b/packages/php-wasm/node/src/lib/load-runtime.ts @@ -2,28 +2,26 @@ import type { SupportedPHPVersion, EmscriptenOptions, PHPRuntime, - RemoteAPI, + OSUserSpaceAPI, + OSUserSpaceContext, + FileLockManager, } from '@php-wasm/universal'; -import { loadPHPRuntime, FSHelpers } from '@php-wasm/universal'; +import { loadPHPRuntime, FSHelpers, bindUserSpace } from '@php-wasm/universal'; import fs from 'fs'; import { getPHPLoaderModule } from '.'; import { withNetworking } from './networking/with-networking'; -import type { FileLockManager } from './file-lock-manager'; import { withXdebug, type XdebugOptions } from './xdebug/with-xdebug'; import { withIntl } from './extensions/intl/with-intl'; import { joinPaths } from '@php-wasm/util'; -import type { Promised } from '@php-wasm/util'; import { dirname } from 'path'; export interface PHPLoaderOptions { - emscriptenOptions?: EmscriptenOptions; followSymlinks?: boolean; withXdebug?: boolean; xdebug?: XdebugOptions; withIntl?: boolean; -} -type PHPLoaderOptionsForNode = PHPLoaderOptions & { + fileLockManager?: FileLockManager; emscriptenOptions?: EmscriptenOptions & { /** * The process ID for the PHP runtime. @@ -35,20 +33,10 @@ type PHPLoaderOptionsForNode = PHPLoaderOptions & { */ processId?: number; - /** - * An optional file lock manager to use for the PHP runtime. - * - * The lock manager is optional when running a single php-wasm process. - * - * When running with JSPI, both synchronous and asynchronous - * file lock managers are supported. - * When running with Asyncify, the file lock manager must be synchronous. - */ - fileLockManager?: - | RemoteAPI - // Allow promised type for testing without providing true RemoteAPI. - | Promised - | FileLockManager; + // TODO: Document this. + bindUserSpace?: ( + userSpaceContext: OSUserSpaceContext + ) => OSUserSpaceAPI; /** * An optional function to collect trace messages. @@ -60,18 +48,12 @@ type PHPLoaderOptionsForNode = PHPLoaderOptions & { trace?: (processId: number, format: string, ...args: any[]) => void; /** - * An optional object to pass to the PHP-WASM library's `init` function. - * - * phpWasmInitOptions.nativeInternalDirPath is used to mount a - * real, native directory as the php-wasm /internal directory. - * - * @see https://github.com/php-wasm/php-wasm/blob/main/compile/php/phpwasm-emscripten-library.js#L100 + * An optional path used to a real, native directory + * to be mounted as the php-wasm /internal directory. */ - phpWasmInitOptions?: { - nativeInternalDirPath?: string; - }; + nativeInternalDirPath?: string; }; -}; +} /** * Does what load() does, but synchronously returns @@ -82,7 +64,7 @@ type PHPLoaderOptionsForNode = PHPLoaderOptions & { */ export async function loadNodeRuntime( phpVersion: SupportedPHPVersion, - options: PHPLoaderOptionsForNode = {} + options: PHPLoaderOptions = {} ) { // TODO: Throw an error if a file lock manager is provided but not a process ID. @@ -95,6 +77,14 @@ export async function loadNodeRuntime( quit: function (code, error) { throw error; }, + bindUserSpace: (userSpaceContext: OSUserSpaceContext) => { + return bindUserSpace( + { + fileLockManager: options?.fileLockManager, + }, + userSpaceContext + ); + }, ...(options.emscriptenOptions || {}), onRuntimeInitialized: (phpRuntime: PHPRuntime) => { /** diff --git a/packages/php-wasm/node/src/test/file-lock-manager-for-node.spec.ts b/packages/php-wasm/node/src/test/file-lock-manager-for-node.spec.ts index ea1fe556a1..b9c9aa4a39 100644 --- a/packages/php-wasm/node/src/test/file-lock-manager-for-node.spec.ts +++ b/packages/php-wasm/node/src/test/file-lock-manager-for-node.spec.ts @@ -3,7 +3,7 @@ import { FileLockManagerForNode } from '../lib/file-lock-manager-for-node'; import { fork } from 'child_process'; import type { ChildProcess } from 'child_process'; import { join } from 'path'; -import type { WholeFileLockOp } from '../lib/file-lock-manager'; +import { type WholeFileLockOp } from '@php-wasm/universal'; import { flockSync as nativeFlockSync } from 'fs-ext'; const TEST_FILE1 = new URL('test1.txt', import.meta.url).pathname; diff --git a/packages/php-wasm/node/src/test/php-file-locking.spec.ts b/packages/php-wasm/node/src/test/php-file-locking.spec.ts index 85be099855..4fb24a5078 100644 --- a/packages/php-wasm/node/src/test/php-file-locking.spec.ts +++ b/packages/php-wasm/node/src/test/php-file-locking.spec.ts @@ -7,7 +7,10 @@ import { proxyFileSystem, type SupportedPHPVersion, } from '@php-wasm/universal'; -import { SupportedPHPVersions } from '@php-wasm/universal'; +import { + SupportedPHPVersions, + type FileLockManager, +} from '@php-wasm/universal'; import { createNodeFsMountHandler, FileLockManagerForNode, @@ -15,11 +18,11 @@ import { } from '../lib'; import { joinPaths, - wrapSynchronousInterfaceAsPromised, - type Promised, + /* eslint-disable-next-line @typescript-eslint/no-unused-vars -- + * sprintf() is used in a trace function that is commented out by default. + */ + sprintf, } from '@php-wasm/util'; -import { jspi } from 'wasm-feature-detect'; -import type { FileLockManager } from '../lib/file-lock-manager'; const phpVersionsToTest = 'PHP' in process.env @@ -31,16 +34,12 @@ describe.each(phpVersionsToTest)('PHP %s: File locking', (phpVersion) => { let tempDir: string; // TODO: Use one file lock manager per test - let fileLockManager: - | FileLockManagerForNode - | Promised; + let fileLockManager: FileLockManagerForNode; let nextProcessId: number; beforeEach(async () => { tempDir = mkdtempSync(join(tmpdir(), 'php-wasm-file-locking-')); - fileLockManager = (await jspi()) - ? wrapSynchronousInterfaceAsPromised(new FileLockManagerForNode()) - : new FileLockManagerForNode(); + fileLockManager = new FileLockManagerForNode(); nextProcessId = 1; }); afterEach(async () => { @@ -49,9 +48,22 @@ describe.each(phpVersionsToTest)('PHP %s: File locking', (phpVersion) => { async function createPhpRuntimeWithFileLockingAndTestMount(): Promise { const runtimeId = await loadNodeRuntime(phpVersion, { + fileLockManager: fileLockManager!, emscriptenOptions: { processId: nextProcessId++, - fileLockManager: fileLockManager!, + // NOTE: You can uncomment this for debugging test failures. + // trace: function tracePhpWasm( + // processId: number, + // format: string, + // ...args: any[] + // ) { + // // eslint-disable-next-line no-console + // console.log( + // performance.now().toFixed(6).padStart(15, '0'), + // processId.toString().padStart(16, '0'), + // sprintf(format, ...args) + // ); + // }, }, }); const php = new PHP(runtimeId); @@ -89,7 +101,7 @@ error_log = ${errorLogPath} `, }); // TODO: Why does this DB file check fail for PHP 8.0 and under? The tests pass. The DB must exist. - // This is only a problem in JSPI builds. Sleeping for 500ms avoids the issue. + // This is only a problem in JSPI builds. Sleeping for 501ms avoids the issue. // const dbFilePath = join(tempDir, dbFileName); // if (!existsSync(dbFilePath)) { // throw new Error(`Database file not created: ${dbFilePath}`); @@ -123,7 +135,7 @@ error_log = ${errorLogPath} $db = new SQLite3('${vfsDbFilePath}'); $db->exec('BEGIN EXCLUSIVE;'); - // Wait until php2 notifies us by deleting the sleep file + // Wait until php2 notifies us by updating the coordination file file_put_contents('${vfsPhpCoordinationFile}', '${stages.php1Locked}'); while ( file_get_contents('${vfsPhpCoordinationFile}') !== '${stages.php2ReadyForUnlock}' @@ -1406,23 +1418,19 @@ error_log = ${errorLogPath} }, 5000); describe(`Additional tests with multiple php-wasm instances`, async () => { - const mockFnWithResult = (await jspi()) - ? // Use async mocks for JSPI to match the async FileLockManager - // used by JSPI PHP builds. - (value: any) => vi.fn().mockResolvedValue(value) - : (value: any) => vi.fn().mockReturnValue(value); - function createMockFileLockManager(): FileLockManager { return { - lockWholeFile: mockFnWithResult(true), - lockFileByteRange: mockFnWithResult(true), - findFirstConflictingByteRangeLock: mockFnWithResult(undefined), - releaseLocksForProcessFd: mockFnWithResult(undefined), - releaseLocksForProcess: mockFnWithResult(undefined), + lockWholeFile: vi.fn().mockReturnValue(true), + lockFileByteRange: vi.fn().mockReturnValue(true), + findFirstConflictingByteRangeLock: vi + .fn() + .mockReturnValue(undefined), + releaseLocksForProcessFd: vi.fn().mockReturnValue(undefined), + releaseLocksForProcess: vi.fn().mockReturnValue(undefined), }; } - // TODO: Add tests for fcntl() + // TODO: Test fcntl() somehow. The DB tests should use fcntl(), but explicit tests would be better. test(`should attempt to lock a NODEFS file and a PROXYFS node that wraps a NODEFS file`, async () => { // NOTE: Normally, we would use a single file lock manager across all runtimes, @@ -1431,9 +1439,9 @@ error_log = ${errorLogPath} const ENV = { DOCROOT: '/wordpress' }; const php1 = new PHP( await loadNodeRuntime(phpVersion, { + fileLockManager: fileLockManagerForRuntime1, emscriptenOptions: { ENV, - fileLockManager: fileLockManagerForRuntime1, }, }) ); @@ -1451,7 +1459,7 @@ error_log = ${errorLogPath} const vfsPathToLock = '/wordpress/wp-content/lock-this.txt'; const phpThatAttemptsToLock = ` { const opts = { emscriptenOptions: { ENV: { DOCROOT: '/wordpress' } }, diff --git a/packages/php-wasm/node/src/test/php-instance-manager.spec.ts b/packages/php-wasm/node/src/test/php-instance-manager.spec.ts index 0b6ce8be97..3cdf4ba314 100644 --- a/packages/php-wasm/node/src/test/php-instance-manager.spec.ts +++ b/packages/php-wasm/node/src/test/php-instance-manager.spec.ts @@ -1,6 +1,10 @@ import { RecommendedPHPVersion } from '@wp-playground/common'; import { loadNodeRuntime } from '..'; -import { PHP, PHPProcessManager, SinglePHPInstanceManager } from '@php-wasm/universal'; +import { + PHP, + PHPProcessManager, + SinglePHPInstanceManager, +} from '@php-wasm/universal'; describe('SinglePHPInstanceManager', () => { it('should return the PHP instance passed in the constructor', async () => { @@ -60,9 +64,9 @@ describe('SinglePHPInstanceManager', () => { }); it('should throw an error when neither php nor phpFactory is provided', () => { - expect( - () => new SinglePHPInstanceManager({}) - ).toThrowError(/requires either php or phpFactory/); + expect(() => new SinglePHPInstanceManager({})).toThrowError( + /requires either php or phpFactory/ + ); }); it('should only call the factory once even with concurrent getPrimaryPhp calls', async () => { diff --git a/packages/php-wasm/node/src/test/rotate-php-runtime.spec.ts b/packages/php-wasm/node/src/test/rotate-php-runtime.spec.ts index 64560f3980..31d32df9f3 100644 --- a/packages/php-wasm/node/src/test/rotate-php-runtime.spec.ts +++ b/packages/php-wasm/node/src/test/rotate-php-runtime.spec.ts @@ -28,16 +28,14 @@ describe.each([true, false])( ) => await loadNodeRuntime(phpVersion, { emscriptenOptions: { - phpWasmInitOptions: { - /** - * Test both with a natively mounted /internal directory, which - * is what Playground CLI typically does, and without it, which - * is what playground.wordpress.net does. - */ - nativeInternalDirPath: withNativeInternalDir - ? nativeInternalDirPath - : undefined, - }, + /** + * Test both with a natively mounted /internal directory, which + * is what Playground CLI typically does, and without it, which + * is what playground.wordpress.net does. + */ + nativeInternalDirPath: withNativeInternalDir + ? nativeInternalDirPath + : undefined, }, }); }); diff --git a/packages/php-wasm/supported-php-versions.mjs b/packages/php-wasm/supported-php-versions.mjs index 0d9c05e9c0..b65e5fa71c 100644 --- a/packages/php-wasm/supported-php-versions.mjs +++ b/packages/php-wasm/supported-php-versions.mjs @@ -6,7 +6,7 @@ * @property {string} lastRelease */ -export const lastRefreshed = '2025-12-09T09:34:41.943Z'; +export const lastRefreshed = '2025-12-12T18:44:26.006Z'; /** * @type {PhpVersion[]} diff --git a/packages/php-wasm/universal/src/lib/emscripten-types.ts b/packages/php-wasm/universal/src/lib/emscripten-types.ts index e149cdab8e..d833ee7c18 100644 --- a/packages/php-wasm/universal/src/lib/emscripten-types.ts +++ b/packages/php-wasm/universal/src/lib/emscripten-types.ts @@ -149,7 +149,7 @@ export namespace Emscripten { export interface Mount { type: Emscripten.FileSystemType; - opts: object; + opts: Record; mountpoint: string; mounts: Mount[]; root: FSNode; @@ -185,6 +185,10 @@ export namespace Emscripten { write: boolean; readonly isFolder: boolean; readonly isDevice: boolean; + + // NOTE: As of 2025-11-11, this property is added by a php-wasm patch + // for NODEFS.createNode(). It is not part of the Emscripten FSNode interface. + readonly isSharedFS?: boolean; } export interface ErrnoError extends Error { @@ -394,6 +398,7 @@ export namespace Emscripten { export declare const MEMFS: Emscripten.FileSystemType; export declare const NODEFS: Emscripten.FileSystemType; export declare const IDBFS: Emscripten.FileSystemType; + export declare const PROXYFS: Emscripten.FileSystemType; // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html type StringToType = R extends Emscripten.JSType diff --git a/packages/php-wasm/node/src/lib/file-lock-manager.ts b/packages/php-wasm/universal/src/lib/file-lock-manager.ts similarity index 100% rename from packages/php-wasm/node/src/lib/file-lock-manager.ts rename to packages/php-wasm/universal/src/lib/file-lock-manager.ts diff --git a/packages/php-wasm/universal/src/lib/index.ts b/packages/php-wasm/universal/src/lib/index.ts index 827d08ef92..65d48c28b4 100644 --- a/packages/php-wasm/universal/src/lib/index.ts +++ b/packages/php-wasm/universal/src/lib/index.ts @@ -97,4 +97,10 @@ export { sandboxedSpawnHandlerFactory } from './sandboxed-spawn-handler-factory' export * from './api'; export type { WithAPIState as WithIsReady } from './api'; + +export type * from './file-lock-manager'; +// TODO: Review exported names and improve if needed. +export * from './os-user-space'; +export type * from './os-user-space'; + export type { Remote } from './comlink-sync'; diff --git a/packages/php-wasm/universal/src/lib/os-kernel-space.ts b/packages/php-wasm/universal/src/lib/os-kernel-space.ts new file mode 100644 index 0000000000..f377acfb81 --- /dev/null +++ b/packages/php-wasm/universal/src/lib/os-kernel-space.ts @@ -0,0 +1,11 @@ +// TODO: Consider merging FileLockManager file with os-kernel-space. +import type { FileLockManager } from './file-lock-manager'; + +// TODO: Consider merging FileLockManager into this type. +export class OSKernelSpace { + readonly fileLockManager: FileLockManager | undefined; + + constructor(fileLockManager: FileLockManager) { + this.fileLockManager = fileLockManager; + } +} diff --git a/packages/php-wasm/universal/src/lib/os-user-space.ts b/packages/php-wasm/universal/src/lib/os-user-space.ts new file mode 100644 index 0000000000..e79b2a9442 --- /dev/null +++ b/packages/php-wasm/universal/src/lib/os-user-space.ts @@ -0,0 +1,937 @@ +// TODO: Move file manager into kernel space. +// TODO: Move FileLockManager into php-wasm/universal to resolve this +import type { + RequestedRangeLock, + WholeFileLock, + WholeFileLockOp, +} from './file-lock-manager'; +import type { Emscripten } from './emscripten-types'; +import type { OSKernelSpace } from './os-kernel-space'; + +type FSNode = Emscripten.FS.FSNode; + +type NonZeroNumber = Exclude; +type ResultTuple = + | [value: T, errorCode: 0] + | [value: never, errorCode: NonZeroNumber]; + +// TODO: Consider better name than OSUserSpace. Maybe WasmUserSpace, SystemUserSpace, etc? +export type OSUserSpaceContext = { + pid: number; + // TODO: When receiving this context, validate that all these fields exist. + constants: { + F_RDLCK: number; + F_WRLCK: number; + F_UNLCK: number; + F_GETFL: number; + O_ACCMODE: number; + O_RDONLY: number; + O_WRONLY: number; + O_APPEND: number; + O_NONBLOCK: number; + F_SETFL: number; + F_GETLK: number; + F_SETLK: number; + F_SETLKW: number; + SEEK_SET: number; + SEEK_CUR: number; + SEEK_END: number; + // TODO: Move these values to ES prefix or someplace like that. + // Emscripten does not expose these constants to JS, so we hardcode them here. + // Based on + // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 + LOCK_SH: 1; + LOCK_EX: 2; + LOCK_NB: 4; + LOCK_UN: 8; + }; + errnoCodes: { + EBADF: NonZeroNumber; + EINVAL: NonZeroNumber; + EAGAIN: NonZeroNumber; + EDEADLK: NonZeroNumber; + EWOULDBLOCK: NonZeroNumber; + }; + memory: { + HEAP8: Int8Array; + HEAPU8: Uint8Array; + HEAP16: Int16Array; + HEAPU16: Uint16Array; + HEAP32: Int32Array; + HEAPU32: Uint32Array; + HEAPF32: Float32Array; + HEAP64: BigInt64Array; + HEAPU64: BigUint64Array; + HEAPF64: Float64Array; + }; + // This is a collection of functions present in built php-wasm JS. + // By receiving the entire collection here, we can avoid recompiling + // php-wasm JS whenever we add a new dependency from this collection. + wasmImports: { + builtin_fcntl64: (fd: number, cmd: number, varargs?: any) => number; + builtin_fd_close: (fd: number) => number; + js_wasm_trace: (...args: any[]) => void; + }; + // This is a collection of functions present in built php-wasm JS. + // By receiving the entire collection here, we can avoid recompiling + // php-wasm JS whenever we add a new dependency from this collection. + wasmExports: { + wasm_get_end_offset: (fd: number) => bigint; + }; + // This is a collection of functions present in built php-wasm JS. + // By receiving the entire collection here, we can avoid recompiling + // php-wasm JS whenever we add a new dependency from this collection. + syscalls: { + getStreamFromFD: (fd: number) => Emscripten.FS.FSStream; + }; + FS: typeof Emscripten.FS; + PROXYFS: typeof Emscripten.PROXYFS & { + // TODO: Add this method to our main Emscripten FS types + realPath(node: FSNode): string; + }; + NODEFS: typeof Emscripten.NODEFS & { + // TODO: Add this method to our main Emscripten FS types + realPath(node: FSNode): string; + }; +}; + +export type OSUserSpaceAPI = { + fcntl64: (fd: number, cmd: number, varargs?: number) => number; + flock: (fd: number, op: number) => number; + fd_close: (fd: number) => number; + js_release_file_locks: () => void; +}; + +export function bindUserSpace( + { fileLockManager }: OSKernelSpace, + { + pid, + memory: { HEAP16, HEAP64, HEAP32 }, + constants: { + F_RDLCK, + F_WRLCK, + F_UNLCK, + F_GETFL, + O_ACCMODE, + O_RDONLY, + O_WRONLY, + O_APPEND, + O_NONBLOCK, + F_SETFL, + F_GETLK, + F_SETLK, + F_SETLKW, + SEEK_SET, + SEEK_CUR, + SEEK_END, + LOCK_SH, + LOCK_EX, + LOCK_NB, + LOCK_UN, + }, + errnoCodes: { EBADF, EINVAL, EAGAIN, EDEADLK, EWOULDBLOCK }, + wasmImports: { builtin_fcntl64, builtin_fd_close, js_wasm_trace }, + wasmExports: { wasm_get_end_offset }, + syscalls: { getStreamFromFD }, + FS, + PROXYFS, + NODEFS, + }: OSUserSpaceContext +): OSUserSpaceAPI { + class VarArgsAccessor { + argsAddr: number; + + constructor(argsAddr: number) { + this.argsAddr = argsAddr; + } + + getNextAsPointer(): number { + return this.getNextAsInt(); + } + + getNextAsInt(): number { + // Shift right by 2 to divide by 2^2. + const fourByteOffset = this.argsAddr >> 2; + const value = HEAP32[fourByteOffset]; + this.argsAddr += 4; + return value; + } + } + + type FcntlLockState = typeof F_RDLCK | typeof F_WRLCK | typeof F_UNLCK; + const locking = { + /* + * This is a set of possibly locked file descriptors. + * + * When a file descriptor is closed, we need to release any associated held by this process. + * Instead of trying remember and forget file descriptors as they are locked and unlocked, + * we just track file descriptors we have locked before and try an unlock when they are closed. + */ + maybeLockedFds: new Set(), + + lockStateToFcntl: { + shared: F_RDLCK, + exclusive: F_WRLCK, + unlocked: F_UNLCK, + } as const satisfies Record, + fcntlToLockState: { + [F_RDLCK as FcntlLockState]: 'shared', + [F_WRLCK as FcntlLockState]: 'exclusive', + [F_UNLCK as FcntlLockState]: 'unlocked', + } as const satisfies Record, + is_path_to_shared_fs(path: string) { + const { node } = FS.lookupPath(path, { noent_okay: true }); + if (!node) { + return false; + } + + if (node.mount.type !== PROXYFS) { + return !!node.isSharedFS; + } + + // TODO: Do we still need to support PROXYFS now that Playground CLI uses NODEFS everywhere? + // This looks like a PROXYFS node. Let's try a lookup. + const nodePath = PROXYFS.realPath(node); + const backingFs = node?.mount?.opts?.['fs']; + if (backingFs) { + // Tolerate ENOENT because looking up a MEMFS node by path always fails. + const { node: backingNode } = backingFs.lookupPath(nodePath, { + noent_okay: true, + }); + return !!backingNode?.isSharedFS; + } + + return false; + }, + get_fd_access_mode(fd: number) { + return builtin_fcntl64(fd, F_GETFL) & O_ACCMODE; + }, + get_vfs_path_from_fd(fd: number): ResultTuple { + try { + return [FS.readlink(`/proc/self/fd/${fd}`), 0]; + } catch { + return [null as never, EBADF] as const; + } + }, + + get_native_path_from_vfs_path(vfsPath: string) { + const { node } = FS.lookupPath(vfsPath, { + noent_okay: true, + }); + if (!node) { + throw new Error(`No node found for VFS path ${vfsPath}`); + } + if (node.mount.type === NODEFS) { + return NODEFS.realPath(node); + } else if (node.mount.type === PROXYFS) { + // TODO: Tolerate ENOENT here? + const { node: backingNode, path: backingPath } = + node.mount.opts['fs'].lookupPath(vfsPath); + js_wasm_trace( + 'backingNode for %s: %s', + vfsPath, + backingPath, + backingNode + ); + return backingNode.mount.type.realPath(backingNode); + } else { + throw new Error( + `Unsupported filesystem type for path ${vfsPath}` + ); + } + }, + + check_lock_params(fd: number, l_type: number) { + const accessMode = locking.get_fd_access_mode(fd); + if ( + (l_type === F_WRLCK && accessMode === O_RDONLY) || + (l_type === F_RDLCK && accessMode === O_WRONLY) + ) { + js_wasm_trace( + 'check_lock_params(%d, %d, %d) EBADF', + fd, + l_type, + accessMode + ); + return EBADF; + } + + return 0; + }, + }; + + type FlockStruct = { + l_type: number; + l_whence: number; + l_start: bigint; + l_len: bigint; + l_pid: number; + }; + + // NOTE: With the exception of l_type, these offsets are not exposed to + // JS by Emscripten, so we hardcode them here. + // We name them with snake case to better reflect the struct field names. + const emscripten_flock_l_type_offset = 0; + const emscripten_flock_l_whence_offset = 2; + const emscripten_flock_l_start_offset = 8; + const emscripten_flock_l_len_offset = 16; + const emscripten_flock_l_pid_offset = 24; + + /** + * Read the flock struct at the given address. + * + * @param {bigint} flockStructAddress - the address of the flock struct + * @returns the flock struct + */ + // TODO: Does this arg type need to be a bigint? + function readFlockStruct(flockStructAddress: number) { + /* + * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, + * we need to adjust offsets to address the word size of each HEAP. + * + * For example, an offset of 64 bytes is the following for each HEAP: + * - HEAP8: 64 (the 64th byte) + * - HEAP16: 32 (the 32nd 16-bit word) + * - HEAP32: 16 (the 16th 32-bit word) + * - HEAP64: 8 (the 8th 64-bit word) + * + * We get a word offset by dividing the byte offset by the word size. + */ + return { + l_type: HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_type_offset) >> 1 + ], + l_whence: + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 + ], + l_start: + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_start_offset) >> 3 + ], + l_len: HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_len_offset) >> 3 + ], + l_pid: HEAP32[ + // Shift right by 2 to divide by 2^2. + (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 + ], + }; + } + + /** + * Update the flock struct at the given address with the given fields. + * + * @param {bigint} flockStructAddress - the address of the flock struct + * @param {object} fields - the fields to update + */ + function updateFlockStruct( + flockStructAddress: number, + fields: Partial + ) { + /* + * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, + * we need to adjust offsets to address the word size of each HEAP. + * + * For example, an offset of 64 bytes is the following for each HEAP: + * - HEAP8: 64 (the 64th byte) + * - HEAP16: 32 (the 32nd 16-bit word) + * - HEAP32: 16 (the 16th 32-bit word) + * - HEAP64: 8 (the 8th 64-bit word) + * + * We get a word offset by dividing the byte offset by the word size. + */ + if (fields.l_type !== undefined) { + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_type_offset) >> 1 + ] = fields.l_type; + } + if (fields.l_whence !== undefined) { + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 + ] = fields.l_whence; + } + if (fields.l_start !== undefined) { + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_start_offset) >> 3 + ] = fields.l_start; + } + if (fields.l_len !== undefined) { + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_len_offset) >> 3 + ] = fields.l_len; + } + if (fields.l_pid !== undefined) { + HEAP32[ + // Shift right by 2 to divide by 2^2. + (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 + ] = fields.l_pid; + } + } + + /** + * Resolve the base address of the range depending on the whence and start offset. + * + * @param {number} fd - the file descriptor + * @param {number} whence - what the start offset is relative to + * @param {bigint} startOffset - the offset from the whence + * @returns The resolved offset and the errno. If there is an error, + * the resolved offset is null, and the errno is non-zero. + */ + function getBaseAddress(fd: number, whence: number, startOffset: bigint) { + let baseAddress; + switch (whence) { + case SEEK_SET: + baseAddress = 0n; + break; + case SEEK_CUR: + try { + const stream = getStreamFromFD(fd); + baseAddress = FS.llseek(stream, 0, whence); + } catch (e) { + js_wasm_trace( + 'get_base_address(%d, %d, %d) getStreamFromFD error %s', + fd, + whence, + startOffset, + e + ); + return [null, EINVAL]; + } + break; + case SEEK_END: + baseAddress = wasm_get_end_offset(fd); + break; + default: + return [null, EINVAL]; + } + + if (baseAddress == -1) { + // We cannot resolve the offset within the file. + // Let's treat this as a problem with the file descriptor. + return [null, EBADF]; + } + + const resolvedOffset = baseAddress + startOffset; + if (resolvedOffset < 0) { + // This is not a valid offset. Report args as invalid. + return [null, EINVAL]; + } + + return [resolvedOffset, 0]; + } + + // TODO: Should command just be a string representation of const name? + function fcntl64(fd: number, cmd: number, varargs?: number) { + js_wasm_trace('fcntl64(%d, %d)', fd, cmd); + if (!fileLockManager) { + js_wasm_trace( + 'fcntl64(%d, %d) file lock manager is not available. ' + + 'delegate to Emscripten builtin fcntl64.', + fd, + cmd + ); + return builtin_fcntl64(fd, cmd, varargs); + } + + switch (cmd) { + case F_GETLK: { + const reportUnlockedFileByDefault = + function reportUnlockedFileByDefault() { + updateFlockStruct(flockStructAddr, { + l_type: F_UNLCK, + }); + return 0; + }; + + js_wasm_trace('fcntl(%d, F_GETLK)', fd); + const [vfsPath, vfsPathErrno] = + locking.get_vfs_path_from_fd(fd); + if (vfsPathErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', + fd, + vfsPath, + vfsPathErrno + ); + return -EBADF; + } + + const varArgsAccessor = new VarArgsAccessor(varargs!); + const flockStructAddr = varArgsAccessor.getNextAsPointer(); + + if ( + !locking.is_path_to_shared_fs(vfsPath) || + fileLockManager === undefined + ) { + js_wasm_trace( + "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", + fd, + vfsPath + ); + + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + return reportUnlockedFileByDefault(); + } + + const flockStruct = readFlockStruct(flockStructAddr); + + if (!(flockStruct.l_type in locking.fcntlToLockState)) { + return -EINVAL; + } + + const paramsCheckErrno = locking.check_lock_params( + fd, + flockStruct.l_type + ); + if (paramsCheckErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', + fd, + vfsPath, + paramsCheckErrno + ); + return -EINVAL; + } + + const requestedLockType = + locking.fcntlToLockState[flockStruct.l_type]; + const [absoluteStartOffset, baseAddressErrno] = getBaseAddress( + fd, + flockStruct.l_whence, + flockStruct.l_start + ); + if (baseAddressErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s get_base_address errno %d', + fd, + vfsPath, + baseAddressErrno + ); + return -EINVAL; + } + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + const conflictingLock = + fileLockManager.findFirstConflictingByteRangeLock( + nativeFilePath, + { + type: requestedLockType, + start: absoluteStartOffset, + end: absoluteStartOffset + flockStruct.l_len, + pid, + } + ); + if (conflictingLock === undefined) { + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', + fd, + vfsPath, + absoluteStartOffset, + absoluteStartOffset + flockStruct.l_len + ); + + updateFlockStruct(flockStructAddr, { + l_type: F_UNLCK, + }); + return 0; + } + + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', + fd, + vfsPath, + conflictingLock.type, + conflictingLock.start, + conflictingLock.end, + conflictingLock.pid + ); + + const fcntlLockState = + locking.lockStateToFcntl[conflictingLock.type]; + updateFlockStruct(flockStructAddr, { + l_type: fcntlLockState, + l_whence: SEEK_SET, + l_start: conflictingLock.start, + l_len: BigInt( + conflictingLock.end - conflictingLock.start + ), + l_pid: conflictingLock.pid, + }); + return 0; + } catch (e) { + js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', + fd, + vfsPath, + e + ); + return -EINVAL; + } + } + // @TODO: Implement a blocking version of F_SETLKW instead of + // treating it the same as F_SETLK. + case F_SETLKW: + case F_SETLK: { + js_wasm_trace('fcntl(%d, F_SETLK)', fd); + const [vfsPath, vfsPathErrno] = + locking.get_vfs_path_from_fd(fd); + if (vfsPathErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', + fd, + vfsPath, + vfsPathErrno + ); + return -vfsPathErrno; + } + + if (!locking.is_path_to_shared_fs(vfsPath)) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', + fd, + vfsPath + ); + + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + return 0; + } + + const varArgsAccessor = new VarArgsAccessor(varargs!); + const flockStructAddr = varArgsAccessor.getNextAsPointer(); + const flockStruct = readFlockStruct(flockStructAddr); + + const [absoluteStartOffset, baseAddressErrno] = getBaseAddress( + fd, + flockStruct.l_whence, + flockStruct.l_start + ); + if (baseAddressErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s get_base_address errno %d', + fd, + vfsPath, + baseAddressErrno + ); + return -EINVAL; + } + + if (!(flockStruct.l_type in locking.fcntlToLockState)) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s invalid lock type %d', + fd, + vfsPath, + flockStruct.l_type + ); + return -EINVAL; + } + + const paramsCheckErrno = locking.check_lock_params( + fd, + flockStruct.l_type + ); + if (paramsCheckErrno !== 0) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', + fd, + vfsPath, + paramsCheckErrno + ); + return -paramsCheckErrno; + } + + locking.maybeLockedFds.add(fd); + + const requestedLockType = + locking.fcntlToLockState[flockStruct.l_type]; + const rangeLock: RequestedRangeLock = { + type: requestedLockType, + start: absoluteStartOffset, + end: absoluteStartOffset + flockStruct.l_len, + pid, + }; + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', + fd, + vfsPath, + rangeLock + ); + + const succeeded = fileLockManager.lockFileByteRange( + nativeFilePath, + rangeLock + ); + + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', + fd, + vfsPath, + succeeded, + rangeLock + ); + return succeeded ? 0 : -EAGAIN; + } catch (e) { + js_wasm_trace( + 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', + fd, + vfsPath, + e, + rangeLock + ); + return -EINVAL; + } + } + case F_SETFL: { + /** + * Overrides the core Emscripten implementation to reflect what + * fcntl does in linux kernel. This implementation is still missing + * a bunch of nuance, but, unlike the core Emscripten implementation, + * it overrides the stream flags while preserving non-stream flags. + * + * @see fcntl.c: + * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 + */ + let arg = 0; + if (varargs !== undefined) { + const varArgsAccessor = new VarArgsAccessor(varargs); + arg = varArgsAccessor.getNextAsInt(); + } + + const stream = getStreamFromFD(fd); + + // Update the stream flags + const SETFL_MASK = O_APPEND | O_NONBLOCK; + stream.flags = + (arg & SETFL_MASK) | (stream.flags & ~SETFL_MASK); + + return 0; + } + default: + return builtin_fcntl64(fd, cmd, varargs); + } + } + + function flock(fd: number, op: number) { + js_wasm_trace('js_flock(%d, %d)', fd, op); + if (!fileLockManager) { + js_wasm_trace( + 'js_flock(%d, %d) file lock manager is not available. ' + + 'succeed by default as Emscripten does.', + fd, + op + ); + return 0; + } + + type FlockOp = typeof LOCK_SH | typeof LOCK_EX | typeof LOCK_UN; + const flockToLockOpType = { + [LOCK_SH]: 'shared', + [LOCK_EX]: 'exclusive', + [LOCK_UN]: 'unlock', + } as const satisfies Record; + + const [vfsPath, vfsPathErrno] = locking.get_vfs_path_from_fd(fd); + if (vfsPathErrno !== 0) { + js_wasm_trace( + 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', + fd, + op, + vfsPath, + vfsPathErrno + ); + return -vfsPathErrno; + } + + if (!locking.is_path_to_shared_fs(vfsPath)) { + js_wasm_trace( + 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', + fd, + op, + vfsPath + ); + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + return 0; + } + + const paramsCheckErrno = locking.check_lock_params(fd, op); + if (paramsCheckErrno !== 0) { + js_wasm_trace( + 'js_flock(%d, %d) %s check_lock_params errno %d', + fd, + op, + vfsPath, + paramsCheckErrno + ); + return -paramsCheckErrno; + } + + // @TODO: Consider supporting blocking mode of flock() + if ((op & LOCK_NB) === 0) { + js_wasm_trace( + 'js_flock(%d, %d) blocking mode of flock() is not implemented', + fd, + op + ); + // We do not yet support the blocking form of flock(). + // We respond with EINVAL to indicate failure + // because it is a known errno for a failed blocking flock(). + // return -EINVAL; + // TODO: Implement blocking mode of flock() + return 0; + } + + const maskedOp = op & ((LOCK_SH | LOCK_EX | LOCK_UN) as FlockOp | 0); + + if (maskedOp === 0) { + js_wasm_trace('js_flock(%d, %d) invalid flock() operation', fd, op); + return -EINVAL; + } + + const lockOpType = flockToLockOpType[maskedOp as FlockOp]; + if (lockOpType === undefined) { + js_wasm_trace('js_flock(%d, %d) invalid flock() operation', fd, op); + return -EINVAL; + } + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + const succeeded = fileLockManager.lockWholeFile(nativeFilePath, { + type: lockOpType, + pid: pid, + fd, + }); + js_wasm_trace( + 'js_flock(%d, %d) lockWholeFile %s returned %d', + fd, + op, + vfsPath, + succeeded + ); + if (succeeded) { + locking.maybeLockedFds.add(fd); + } + return succeeded ? 0 : -EWOULDBLOCK; + } catch (e) { + js_wasm_trace('js_flock(%d, %d) lockWholeFile error %s', fd, op, e); + return -EINVAL; + } + } + + function fd_close(fd: number) { + if (!fileLockManager) { + js_wasm_trace( + 'fd_close(%d) file lock manager is not available. ' + + 'delegate to Emscripten builtin fd_close.', + fd + ); + return builtin_fd_close(fd); + } + + // We have to get the VFS path from the file descriptor + // before closing it. + const [vfsPath, vfsPathResolutionErrno] = + locking.get_vfs_path_from_fd(fd); + + const fdCloseResult = builtin_fd_close(fd); + if (fdCloseResult !== 0) { + js_wasm_trace( + 'fd_close(%d) %s result %d', + fd, + vfsPath, + fdCloseResult + ); + return fdCloseResult; + } + if (!locking.maybeLockedFds.has(fd)) { + js_wasm_trace( + 'fd_close(%d) not in maybe-locked-list %s result %d', + fd, + vfsPath, + fdCloseResult + ); + return fdCloseResult; + } + + if (vfsPathResolutionErrno !== 0) { + js_wasm_trace( + 'fd_close(%d) get_vfs_path_from_fd error %d', + fd, + vfsPathResolutionErrno + ); + /* + * It looks like the file may have had an associated lock, + * but since we cannot look up the path, + * there is nothing more for us to do. + * + * NOTE: This seems possible for files that are locked and + * then unlinked before close. It is an opportunity for a + * lock to be orphaned in the lock manager. + * @TODO: Explore how to ensure cleanup in this case. + */ + return fdCloseResult; + } + + if (!locking.is_path_to_shared_fs(vfsPath)) { + return fdCloseResult; + } + + try { + js_wasm_trace('fd_close(%d) %s release locks', fd, vfsPath); + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + fileLockManager.releaseLocksForProcessFd(pid, fd, nativeFilePath); + js_wasm_trace('fd_close(%d) %s release locks success', fd, vfsPath); + } catch (e) { + js_wasm_trace("fd_close(%d) %s error '%s'", fd, vfsPath, e); + } + return fdCloseResult; + } + + // TODO: Implement based on current process + // TODO: Replace with process exit handler + function js_release_file_locks() { + js_wasm_trace('js_release_file_locks()'); + if (pid === undefined) { + js_wasm_trace('js_release_file_locks pid is undefined'); + return; + } + if (fileLockManager === undefined) { + js_wasm_trace( + 'js_release_file_locks file lock manager is undefined' + ); + return; + } + + try { + fileLockManager.releaseLocksForProcess(pid); + js_wasm_trace('js_release_file_locks succeeded'); + } catch (e) { + js_wasm_trace('js_release_file_locks error %s', e); + } + } + + return { + fcntl64, + flock, + fd_close, + js_release_file_locks, + }; +} diff --git a/packages/php-wasm/universal/tsconfig.json b/packages/php-wasm/universal/tsconfig.json index fe794238d4..18d7a4b681 100644 --- a/packages/php-wasm/universal/tsconfig.json +++ b/packages/php-wasm/universal/tsconfig.json @@ -4,7 +4,9 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + // "noPropertyAccessFromIndexSignature": true, + // TODO: Why do we want to avoid property access from index signature? + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "types": ["vitest", "vite/client"] diff --git a/packages/playground/blueprints/src/lib/v1/resources.ts b/packages/playground/blueprints/src/lib/v1/resources.ts index 13552a8ac5..ecff6a7c54 100644 --- a/packages/playground/blueprints/src/lib/v1/resources.ts +++ b/packages/playground/blueprints/src/lib/v1/resources.ts @@ -240,7 +240,7 @@ export abstract class Resource { } export abstract class ResourceDecorator< - T extends File | Directory + T extends File | Directory, > extends Resource { protected resource: Resource; constructor(resource: Resource) { @@ -770,7 +770,7 @@ export function toDirectoryZipName(rawInput: string) { * A decorator for a resource that adds caching functionality. */ export class CachedResource< - T extends File | Directory + T extends File | Directory, > extends ResourceDecorator { protected override promise?: Promise; @@ -788,7 +788,7 @@ export class CachedResource< * through a semaphore. */ export class SemaphoreResource< - T extends File | Directory + T extends File | Directory, > extends ResourceDecorator { private readonly semaphore: Semaphore; constructor(resource: Resource, semaphore: Semaphore) { diff --git a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts index fcfe4efd9d..aa9ac5e763 100644 --- a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts +++ b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts @@ -1,10 +1,9 @@ -import type { FileLockManager } from '@php-wasm/node'; +import type { FileLockManager } from '@php-wasm/universal'; import { loadNodeRuntime } from '@php-wasm/node'; import { EmscriptenDownloadMonitor } from '@php-wasm/progress'; -import type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal'; +import type { SupportedPHPVersion } from '@php-wasm/universal'; import { PHPWorker, - consumeAPI, consumeAPISync, exposeAPI, sandboxedSpawnHandlerFactory, @@ -17,7 +16,6 @@ import { bootWordPressAndRequestHandler, } from '@wp-playground/wordpress'; import { rootCertificates } from 'tls'; -import { jspi } from 'wasm-feature-detect'; import { MessageChannel, type MessagePort, parentPort } from 'worker_threads'; import { mountResources } from '../mounts'; import { logger } from '@php-wasm/logger'; @@ -87,7 +85,7 @@ function tracePhpWasm(processId: number, format: string, ...args: any[]) { export class PlaygroundCliBlueprintV1Worker extends PHPWorker { booted = false; - fileLockManager: RemoteAPI | FileLockManager | undefined; + fileLockManager: FileLockManager | undefined; constructor(monitor: EmscriptenDownloadMonitor) { super(undefined, monitor); @@ -103,27 +101,15 @@ export class PlaygroundCliBlueprintV1Worker extends PHPWorker { * @see phpwasm-emscripten-library-file-locking-for-node.js */ async useFileLockManager(port: MessagePort) { - if (await jspi()) { - /** - * If JSPI is available, php.js supports both synchronous and asynchronous locking syscalls. - * Web browsers, however, only support asynchronous message passing so let's use the - * asynchronous API. Every method call will return a promise. - * - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - this.fileLockManager = consumeAPI(port); - } else { - /** - * If JSPI is not available, php.js only supports synchronous locking syscalls. - * Let's use the synchronous API. Every method call will block this thread - * until the result is available. - * - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - this.fileLockManager = await consumeAPISync(port); - } + /** + * If JSPI is not available, php.js only supports synchronous locking syscalls. + * Let's use the synchronous API. Every method call will block this thread + * until the result is available. + * + * @see comlink-sync.ts + * @see phpwasm-emscripten-library-file-locking-for-node.js + */ + this.fileLockManager = await consumeAPISync(port); } async bootAndSetUpInitialWorker(options: PrimaryWorkerBootOptions) { @@ -285,8 +271,8 @@ function createPhpRuntimeFactory( return await loadNodeRuntime( options.phpVersion || RecommendedPHPVersion, { + fileLockManager, emscriptenOptions: { - fileLockManager, processId, trace: options.trace ? tracePhpWasm : undefined, phpWasmInitOptions: { diff --git a/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts b/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts index e99e72587d..5a80c16c71 100644 --- a/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts +++ b/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts @@ -1,5 +1,5 @@ import { errorLogPath, logger } from '@php-wasm/logger'; -import type { FileLockManager } from '@php-wasm/node'; +import type { FileLockManager } from '@php-wasm/universal'; import { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node'; import { EmscriptenDownloadMonitor } from '@php-wasm/progress'; import type { @@ -13,7 +13,6 @@ import { PHPExecutionFailureError, PHPResponse, PHPWorker, - consumeAPI, consumeAPISync, exposeAPI, sandboxedSpawnHandlerFactory, @@ -33,7 +32,6 @@ import { existsSync } from 'fs'; import path from 'path'; import { rootCertificates } from 'tls'; import { MessageChannel, type MessagePort, parentPort } from 'worker_threads'; -import { jspi } from 'wasm-feature-detect'; import { spawnWorkerThread, type RunCLIArgs } from '../run-cli'; import type { PhpIniOptions, @@ -182,7 +180,7 @@ export class PlaygroundCliBlueprintV2Worker extends PHPWorker { booted = false; blueprintTargetResolved = false; phpInstancesThatNeedMountsAfterTargetResolved = new Set(); - fileLockManager: RemoteAPI | FileLockManager | undefined; + fileLockManager: FileLockManager | undefined; constructor(monitor: EmscriptenDownloadMonitor) { super(undefined, monitor); @@ -198,27 +196,15 @@ export class PlaygroundCliBlueprintV2Worker extends PHPWorker { * @see phpwasm-emscripten-library-file-locking-for-node.js */ async useFileLockManager(port: MessagePort) { - if (await jspi()) { - /** - * If JSPI is available, php.js supports both synchronous and asynchronous locking syscalls. - * Web browsers, however, only support asynchronous message passing so let's use the - * asynchronous API. Every method call will return a promise. - * - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - this.fileLockManager = consumeAPI(port); - } else { - /** - * If JSPI is not available, php.js only supports synchronous locking syscalls. - * Let's use the synchronous API. Every method call will block this thread - * until the result is available. - * - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - this.fileLockManager = await consumeAPISync(port); - } + /** + * If JSPI is not available, php.js only supports synchronous locking syscalls. + * Let's use the synchronous API. Every method call will block this thread + * until the result is available. + * + * @see comlink-sync.ts + * @see phpwasm-emscripten-library-file-locking-for-node.js + */ + this.fileLockManager = await consumeAPISync(port); } async bootAndSetUpInitialWorker(args: PrimaryWorkerBootArgs) { @@ -502,14 +488,14 @@ export class PlaygroundCliBlueprintV2Worker extends PHPWorker { } return await loadNodeRuntime(phpVersion, { + fileLockManager: this.fileLockManager!, emscriptenOptions: { - fileLockManager: this.fileLockManager!, processId, trace: trace ? tracePhpWasm : undefined, ENV: { DOCROOT: '/wordpress', }, - phpWasmInitOptions: { nativeInternalDirPath }, + nativeInternalDirPath, }, followSymlinks: allow?.includes('follow-symlinks'), withIntl: withIntl, diff --git a/packages/playground/cli/src/run-cli.ts b/packages/playground/cli/src/run-cli.ts index 5e1caf6620..6ba8c0492e 100644 --- a/packages/playground/cli/src/run-cli.ts +++ b/packages/playground/cli/src/run-cli.ts @@ -7,7 +7,6 @@ import type { } from '@php-wasm/universal'; import { PHPResponse, - exposeAPI, exposeSyncAPI, printDebugDetails, } from '@php-wasm/universal'; @@ -35,7 +34,6 @@ import { LoadBalancer } from './load-balancer'; /* eslint-disable no-console */ import { SupportedPHPVersions } from '@php-wasm/universal'; import { cpus } from 'os'; -import { jspi } from 'wasm-feature-detect'; import type { MessagePort as NodeMessagePort } from 'worker_threads'; import yargs from 'yargs'; import { isValidWordPressSlug } from './is-valid-wordpress-slug'; @@ -1239,25 +1237,16 @@ export function spawnWorkerThread( */ async function exposeFileLockManager(fileLockManager: FileLockManagerForNode) { const { port1, port2 } = new NodeMessageChannel(); - if (await jspi()) { - /** - * When JSPI is available, the worker thread expects an asynchronous API. - * - * @see worker-thread.ts - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - exposeAPI(fileLockManager, null, port1); - } else { - /** - * When JSPI is not available, the worker thread expects a synchronous API. - * - * @see worker-thread.ts - * @see comlink-sync.ts - * @see phpwasm-emscripten-library-file-locking-for-node.js - */ - await exposeSyncAPI(fileLockManager, port1); - } + /** + * Always expose a synchronous API for the file lock manager + * so our injected system call overrides don't have to switch + * between synchronous and asynchronous APIs. + * + * @todo: Fill in the file containing the injected file locking system calls. + * @see comlink-sync.ts + * @see phpwasm-emscripten-library-file-locking-for-node.js + */ + await exposeSyncAPI(fileLockManager, port1); return port2; } diff --git a/packages/playground/cli/tests/file-locking.spec.ts b/packages/playground/cli/tests/file-locking.spec.ts index 915aa8a4fd..a4b3696e42 100644 --- a/packages/playground/cli/tests/file-locking.spec.ts +++ b/packages/playground/cli/tests/file-locking.spec.ts @@ -31,6 +31,9 @@ describe('Playground CLI file locking', () => { ], // Test locking across multiple workers experimentalMultiWorker: MULTI_WORKER_COUNT, + verbosity: 'debug', + // NOTE: You can uncomment this for debugging test failures. + // experimentalTrace: true, }); }, TEST_SUITE_PREP_TIMEOUT); diff --git a/tsconfig.base.json b/tsconfig.base.json index e818ba37f2..cf1f2680d2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,123 +1,90 @@ { - "compileOnSave": false, - "compilerOptions": { - "rootDir": ".", - "sourceMap": true, - "declaration": false, - "moduleResolution": "bundler", - "esModuleInterop": true, - "importHelpers": true, - "resolveJsonModule": true, - "jsx": "react", - "target": "ES2021", - "module": "esnext", - "lib": [ - "ES2022", - "esnext.disposable", - "dom" - ], - "skipLibCheck": true, - "skipDefaultLibCheck": true, - "noPropertyAccessFromIndexSignature": false, - "baseUrl": ".", - "paths": { - "@php-wasm/cli": [ - "packages/php-wasm/cli/src/main.ts" - ], - "@php-wasm/cli-util": [ - "packages/php-wasm/cli-util/src/index.ts" - ], - "@php-wasm/fs-journal": [ - "packages/php-wasm/fs-journal/src/index.ts" - ], - "@php-wasm/logger": [ - "packages/php-wasm/logger/src/index.ts" - ], - "@php-wasm/node": [ - "packages/php-wasm/node/src/index.ts" - ], - "@php-wasm/node-polyfills": [ - "packages/php-wasm/node-polyfills/src/index.ts" - ], - "@php-wasm/private": [ - "packages/php-wasm/private/src/index.ts" - ], - "@php-wasm/progress": [ - "packages/php-wasm/progress/src/index.ts" - ], - "@php-wasm/scopes": [ - "packages/php-wasm/scopes/src/index.ts" - ], - "@php-wasm/stream-compression": [ - "packages/php-wasm/stream-compression/src/index.ts" - ], - "@php-wasm/universal": [ - "packages/php-wasm/universal/src/index.ts" - ], - "@php-wasm/universal/mime-types": [ - "packages/php-wasm/universal/src/lib/mime-types.json" - ], - "@php-wasm/util": [ - "packages/php-wasm/util/src/index.ts" - ], - "@php-wasm/web": [ - "packages/php-wasm/web/src/index.ts" - ], - "@php-wasm/web-service-worker": [ - "packages/php-wasm/web-service-worker/src/index.ts" - ], - "@php-wasm/xdebug-bridge": [ - "packages/php-wasm/xdebug-bridge/src/index.ts" - ], - "@wp-playground/blueprints": [ - "packages/playground/blueprints/src/index.ts" - ], - "@wp-playground/cli": [ - "packages/playground/cli/src/cli.ts" - ], - "@wp-playground/client": [ - "packages/playground/client/src/index.ts" - ], - "@wp-playground/common": [ - "packages/playground/common/src/index.ts" - ], - "@wp-playground/components": [ - "packages/playground/components/src/index.ts" - ], - "@wp-playground/nx-extensions": [ - "packages/nx-extensions/src/index.ts" - ], - "@wp-playground/remote": [ - "packages/playground/remote/src/index.ts" - ], - "@wp-playground/storage": [ - "packages/playground/storage/src/index.ts" - ], - "@wp-playground/sync": [ - "packages/playground/sync/src/index.ts" - ], - "@wp-playground/unit-test-utils": [ - "packages/playground/unit-test-utils/src/index.ts" - ], - "@wp-playground/website": [ - "packages/playground/website/src/index.ts" - ], - "@wp-playground/website-extras": [ - "packages/playground/website-extras/src/php-playground/main.tsx" - ], - "@wp-playground/wordpress": [ - "packages/playground/wordpress/src/index.ts" - ], - "@wp-playground/wordpress-builds": [ - "packages/playground/wordpress-builds/src/index.ts" - ], - "isomorphic-git": [ - "./isomorphic-git" - ] - } - }, - "exclude": [ - "node_modules", - "tmp" - ] -} \ No newline at end of file + "compileOnSave": false, + "compilerOptions": { + "rootDir": ".", + "sourceMap": true, + "declaration": false, + "moduleResolution": "bundler", + "esModuleInterop": true, + "importHelpers": true, + "resolveJsonModule": true, + "jsx": "react", + "target": "ES2021", + "module": "esnext", + "lib": ["ES2022", "esnext.disposable", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "noPropertyAccessFromIndexSignature": false, + "baseUrl": ".", + "paths": { + "@php-wasm/cli": ["packages/php-wasm/cli/src/main.ts"], + "@php-wasm/cli-util": ["packages/php-wasm/cli-util/src/index.ts"], + "@php-wasm/fs-journal": [ + "packages/php-wasm/fs-journal/src/index.ts" + ], + "@php-wasm/logger": ["packages/php-wasm/logger/src/index.ts"], + "@php-wasm/node": ["packages/php-wasm/node/src/index.ts"], + "@php-wasm/node-polyfills": [ + "packages/php-wasm/node-polyfills/src/index.ts" + ], + "@php-wasm/private": ["packages/php-wasm/private/src/index.ts"], + "@php-wasm/progress": ["packages/php-wasm/progress/src/index.ts"], + "@php-wasm/scopes": ["packages/php-wasm/scopes/src/index.ts"], + "@php-wasm/stream-compression": [ + "packages/php-wasm/stream-compression/src/index.ts" + ], + "@php-wasm/universal": ["packages/php-wasm/universal/src/index.ts"], + "@php-wasm/universal/mime-types": [ + "packages/php-wasm/universal/src/lib/mime-types.json" + ], + "@php-wasm/util": ["packages/php-wasm/util/src/index.ts"], + "@php-wasm/web": ["packages/php-wasm/web/src/index.ts"], + "@php-wasm/web-service-worker": [ + "packages/php-wasm/web-service-worker/src/index.ts" + ], + "@php-wasm/xdebug-bridge": [ + "packages/php-wasm/xdebug-bridge/src/index.ts" + ], + "@wp-playground/blueprints": [ + "packages/playground/blueprints/src/index.ts" + ], + "@wp-playground/cli": ["packages/playground/cli/src/cli.ts"], + "@wp-playground/client": [ + "packages/playground/client/src/index.ts" + ], + "@wp-playground/common": [ + "packages/playground/common/src/index.ts" + ], + "@wp-playground/components": [ + "packages/playground/components/src/index.ts" + ], + "@wp-playground/nx-extensions": [ + "packages/nx-extensions/src/index.ts" + ], + "@wp-playground/remote": [ + "packages/playground/remote/src/index.ts" + ], + "@wp-playground/storage": [ + "packages/playground/storage/src/index.ts" + ], + "@wp-playground/sync": ["packages/playground/sync/src/index.ts"], + "@wp-playground/unit-test-utils": [ + "packages/playground/unit-test-utils/src/index.ts" + ], + "@wp-playground/website": [ + "packages/playground/website/src/index.ts" + ], + "@wp-playground/website-extras": [ + "packages/playground/website-extras/src/php-playground/main.tsx" + ], + "@wp-playground/wordpress": [ + "packages/playground/wordpress/src/index.ts" + ], + "@wp-playground/wordpress-builds": [ + "packages/playground/wordpress-builds/src/index.ts" + ], + "isomorphic-git": ["./isomorphic-git"] + } + }, + "exclude": ["node_modules", "tmp"] +}