├── .editorconfig ├── .gitattributes ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .watchmanconfig ├── .yarnrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── android ├── CMakeLists.txt ├── build.gradle ├── cpp-adapter.cpp ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── webassembly │ ├── WebassemblyModule.java │ └── WebassemblyPackage.java ├── app.plugin.js ├── babel.config.js ├── cpp ├── m3_api_libc.c ├── m3_api_libc.h ├── m3_api_meta_wasi.c ├── m3_api_tracer.c ├── m3_api_tracer.h ├── m3_api_uvwasi.c ├── m3_api_wasi.c ├── m3_api_wasi.h ├── m3_bind.c ├── m3_bind.h ├── m3_code.c ├── m3_code.h ├── m3_compile.c ├── m3_compile.h ├── m3_config.h ├── m3_config_platforms.h ├── m3_core.c ├── m3_core.h ├── m3_env.c ├── m3_env.h ├── m3_exception.h ├── m3_exec.c ├── m3_exec.h ├── m3_exec_defs.h ├── m3_function.c ├── m3_function.h ├── m3_info.c ├── m3_info.h ├── m3_math_utils.h ├── m3_module.c ├── m3_parse.c ├── react-native-webassembly.cpp ├── react-native-webassembly.h ├── wasm3.h ├── wasm3_cpp.h └── wasm3_defs.h ├── example ├── .bundle │ └── config ├── .node-version ├── .ruby-version ├── .watchmanconfig ├── Gemfile ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── webassemblyexample │ │ │ │ └── ReactNativeFlipper.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── webassemblyexample │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── release │ │ │ └── java │ │ │ └── com │ │ │ └── webassemblyexample │ │ │ └── ReactNativeFlipper.java │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.d.ts ├── index.js ├── ios │ ├── .xcode.env │ ├── File.swift │ ├── Podfile │ ├── Podfile.lock │ ├── WebassemblyExample-Bridging-Header.h │ ├── WebassemblyExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── WebassemblyExample.xcscheme │ ├── WebassemblyExample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── WebassemblyExample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ └── WebassemblyExampleTests │ │ ├── Info.plist │ │ └── WebassemblyExampleTests.m ├── metro.config.js ├── package.json ├── react-native.config.js ├── src │ ├── App.tsx │ ├── hooks │ │ ├── index.ts │ │ ├── useWasmCircomRuntime.ts │ │ ├── useWasmHelloWorld.ts │ │ └── useWasmUri.ts │ ├── sources │ │ ├── Local.Callback.wasm │ │ ├── Local.Callback.wat │ │ ├── Local.Hello.wasm │ │ ├── Local.SimpleMemory.wasm │ │ └── Local.SimpleMemory.wat │ └── utils │ │ ├── fetchWasm.ts │ │ └── index.ts └── yarn.lock ├── ios ├── Webassembly.h ├── Webassembly.mm └── Webassembly.xcodeproj │ └── project.pbxproj ├── lefthook.yml ├── package.json ├── react-native-webassembly.podspec ├── scripts └── bootstrap.js ├── src ├── __tests__ │ └── index.test.tsx └── index.tsx ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Setup Node.js and install dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Setup Node.js 8 | uses: actions/setup-node@v3 9 | with: 10 | node-version-file: .nvmrc 11 | 12 | - name: Cache dependencies 13 | id: yarn-cache 14 | uses: actions/cache@v3 15 | with: 16 | path: | 17 | **/node_modules 18 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 19 | restore-keys: | 20 | ${{ runner.os }}-yarn- 21 | 22 | - name: Install dependencies 23 | if: steps.yarn-cache.outputs.cache-hit != 'true' 24 | run: | 25 | yarn install --cwd example --frozen-lockfile 26 | yarn install --frozen-lockfile 27 | shell: bash 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Setup 18 | uses: ./.github/actions/setup 19 | 20 | - name: Lint files 21 | run: yarn lint 22 | 23 | - name: Typecheck files 24 | run: yarn typecheck 25 | 26 | test: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | 32 | - name: Setup 33 | uses: ./.github/actions/setup 34 | 35 | - name: Run unit tests 36 | run: yarn test --maxWorkers=2 --coverage 37 | 38 | build: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v3 43 | 44 | - name: Setup 45 | uses: ./.github/actions/setup 46 | 47 | - name: Build package 48 | run: yarn prepack 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Expo 64 | .expo/ 65 | 66 | # Turborepo 67 | .turbo/ 68 | 69 | # generated by bob 70 | lib/ 71 | 72 | *.env 73 | .idea/ 74 | wasm3/ 75 | 76 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.env 2 | .idea/ 3 | wasm3/ 4 | 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.18.1 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [INSERT CONTACT METHOD]. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome, no matter how large or small! 4 | 5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md). 6 | 7 | ## Development workflow 8 | 9 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: 10 | 11 | ```sh 12 | yarn 13 | ``` 14 | 15 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development. 16 | 17 | While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app. 18 | 19 | To start the packager: 20 | 21 | ```sh 22 | yarn example start 23 | ``` 24 | 25 | To run the example app on Android: 26 | 27 | ```sh 28 | yarn example android 29 | ``` 30 | 31 | To run the example app on iOS: 32 | 33 | ```sh 34 | yarn example ios 35 | ``` 36 | 37 | To confirm that the app is running with the new architecture, you can check the Metro logs for a message like this: 38 | 39 | ```sh 40 | Running "WebassemblyExample" with {"fabric":true,"initialProps":{"concurrentRoot":true},"rootTag":1} 41 | ``` 42 | 43 | Note the `"fabric":true` and `"concurrentRoot":true` properties. 44 | 45 | Make sure your code passes TypeScript and ESLint. Run the following to verify: 46 | 47 | ```sh 48 | yarn typecheck 49 | yarn lint 50 | ``` 51 | 52 | To fix formatting errors, run the following: 53 | 54 | ```sh 55 | yarn lint --fix 56 | ``` 57 | 58 | Remember to add tests for your change if possible. Run the unit tests by: 59 | 60 | ```sh 61 | yarn test 62 | ``` 63 | 64 | To edit the Objective-C or Swift files, open `example/ios/WebassemblyExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-webassembly`. 65 | 66 | To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `react-native-webassembly` under `Android`. 67 | 68 | 69 | ### Commit message convention 70 | 71 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: 72 | 73 | - `fix`: bug fixes, e.g. fix crash due to deprecated method. 74 | - `feat`: new features, e.g. add new method to the module. 75 | - `refactor`: code refactor, e.g. migrate from class components to hooks. 76 | - `docs`: changes into documentation, e.g. add usage example for the module.. 77 | - `test`: adding or updating tests, e.g. add integration tests using detox. 78 | - `chore`: tooling changes, e.g. change CI config. 79 | 80 | Our pre-commit hooks verify that your commit message matches this format when committing. 81 | 82 | ### Linting and tests 83 | 84 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/) 85 | 86 | We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing. 87 | 88 | Our pre-commit hooks verify that the linter and tests pass when committing. 89 | 90 | ### Publishing to npm 91 | 92 | We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc. 93 | 94 | To publish new versions, run the following: 95 | 96 | ```sh 97 | yarn release 98 | ``` 99 | 100 | ### Scripts 101 | 102 | The `package.json` file contains various scripts for common tasks: 103 | 104 | - `yarn bootstrap`: setup project by installing all dependencies and pods. 105 | - `yarn typecheck`: type-check files with TypeScript. 106 | - `yarn lint`: lint files with ESLint. 107 | - `yarn test`: run unit tests with Jest. 108 | - `yarn example start`: start the Metro server for the example app. 109 | - `yarn example android`: run the example app on Android. 110 | - `yarn example ios`: run the example app on iOS. 111 | 112 | ### Sending a pull request 113 | 114 | > **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github). 115 | 116 | When you're sending a pull request: 117 | 118 | - Prefer small pull requests focused on one change. 119 | - Verify that linters and tests are passing. 120 | - Review the documentation to make sure it looks good. 121 | - Follow the pull request template when opening a pull request. 122 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue. 123 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 cawfree 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-webassembly 2 | 3 | This package enables [__WebAssembly__](https://webassembly.org/) for [__React Native__](https://reactnative.dev) powered by C++ [__TurboModules__](https://reactnative.dev/docs/next/the-new-architecture/cxx-cxxturbomodules) and [__Wasm3__](https://github.com/wasm3/wasm3), a fast and universal WebAssembly runtime. 4 | 5 | [`react-native-webassembly`](https://github.com/cawfree/react-native-webassembly) provides React Native applications with the capability to execute universal [__Wasm__](https://webassembly.org/) binaries with native speed. 6 | 7 | > ✏️ This project is still in __active development__. The following tasks are still remaining to be completed: 8 | > 9 | > - Sanitize C++ memory management practices. 10 | > - Normalize execution and result handling of userland `export` functions. 11 | > - Test framework implementation. 12 | > 13 | > [__Pull Requests are welcome!__](https://github.com/cawfree/react-native-webassembly/pulls) 🙏 14 | 15 | ### 📡 Installation 16 | 17 | 1. First, ensure your React Native application supports the [__New Architecture__](https://reactnative.dev/docs/new-architecture-intro): 18 | - [__iOS__](https://reactnative.dev/docs/new-architecture-library-ios) 19 | - [__Android__](https://reactnative.dev/docs/new-architecture-library-android) 20 | 2. Install `react-native-webassembly`: 21 | 22 | ```shell 23 | yarn add react-native-webassembly # React Native 24 | npx expo install react-native-webassembly # Expo 25 | ``` 26 | 3. If you're using [__Expo__](https://expo.dev/), don't forget to run `npx expo prebuild` after installing. 27 | 28 | ### ✍️ Usage 29 | 30 | The goal of [`react-native-webassembly`](https://github.com/cawfree/react-native-webassembly) is to export a [__browser-equivalent interface__](https://developer.mozilla.org/en-US/docs/WebAssembly) to the WebAssembly API. 31 | 32 | To initialize a new WebAssembly module, we'll need to `instantiate` an module using a buffer populated with a `.wasm` binary: 33 | 34 | ```typescript 35 | import axios from 'axios'; 36 | import * as WebAssembly from 'react-native-webassembly'; 37 | 38 | import HelloWorld from './hello-world.wasm'; 39 | 40 | const module = await WebAssembly.instantiate<{ 41 | add: (a: number, b: number) => number; 42 | }>(HelloWorld); 43 | ``` 44 | 45 | > **Note** 46 | > 47 | > To import `.wasm` files directly, you will need to [update your `metro.config.js`](https://github.com/cawfree/react-native-webassembly/blob/d9d950e47277e899371a85cd430336a84d96c369/example/metro.config.js#L32). 48 | 49 | Alternatively, in the snippet below, we show how to download and instantiate the reference [__Hello World__](https://github.com/torch2424/wasm-by-example) example stored at a remote location: 50 | 51 | ```typescript 52 | import axios from 'axios'; 53 | import * as WebAssembly from 'react-native-webassembly'; 54 | 55 | const { 56 | data: bufferSource, 57 | } = await axios({ 58 | url: 'https://github.com/torch2424/wasm-by-example/raw/master/examples/hello-world/demo/assemblyscript/hello-world.wasm', 59 | method: 'get', 60 | responseType: 'arraybuffer', 61 | }); 62 | 63 | const module = await WebAssembly.instantiate<{ 64 | add: (a: number, b: number) => number; 65 | }>(bufferSource); 66 | ``` 67 | 68 | You'll notice that in our call to `instantiate`, we can also pass typing information for the `Exports` of the module. In this case, the `hello-world.wasm` binary exports a function to add two numbers, `add`. 69 | 70 | Once configured, we can execute the compiled `wasm` module from our JavaScript code, using the type-safe exported interface: 71 | 72 | ```typescript 73 | module.instance.exports.add(1, 2); // 3. 74 | ``` 75 | 76 | It's also possible to declare an `importObject` to receive callbacks from the compiled module, which declares a list of callback function implementations which can be invoked by the WebAssembly runtime. 77 | 78 | > **Warning** 79 | > 80 | > Some native modules __require__ the presence of certain function implementations. Without specifying module-specific required dependencies, instantiation will fail. 81 | 82 | For example, the [__Circom__](https://github.com/iden3/circom) library converts arithmetic circuits used for generating, evaluating and verifying [__SNARK__](https://consensys.net/blog/developers/introduction-to-zk-snarks/)s are expressed as WASM modules which require the runtime to define an `exceptionHandler` function belonging to the namespace `runtime`. 83 | 84 | It's simple to define an `importObject`: 85 | 86 | ```typescript 87 | const module = await WebAssembly.instantiate<{ 88 | getVersion: () => number; 89 | getFieldNumLen32: () => number; 90 | // ... 91 | }>(bufferSource, { 92 | // Declare custom memory implementation. 93 | env: { 94 | memory: new WebAssembly.Memory({ initial: 32767 }), 95 | }, 96 | // Define the scope of the import functions. 97 | runtime: { 98 | exceptionHandler: (value: number) => console.error(value), 99 | }, 100 | }); 101 | ``` 102 | 103 | Here, we declare an `exceptionHandler` as `runtime` imports to the compiled module. Without declaring this required dependency, the module would fail to compile. 104 | 105 | You can find a working implementation of this process in the [__Example App__](example/src/App.tsx). 106 | 107 | ### 🤔 Memory 108 | 109 | Currently, `wasm3` [__only supports a single memory region__](https://github.com/wasm3/wasm3/blob/772f8f4648fcba75f77f894a6050db121e7651a2/source/wasm3.h#L214). This means that WebAssembly files which contain multiple `memory` allocations are not currently supported. 110 | 111 | [`react-native-webassembly`](https://github.com/cawfree/react-native-webassembly) exposes access to the runtime memory element for allocated instances, which is represented using an `ArrayBuffer` named `memory`. This shares the same backing array as the native runtime. 112 | 113 | It can accessed as follows: 114 | 115 | ```typescript 116 | const module = WebAssembly.instantiate(...); 117 | 118 | const memory: ArrayBuffer | undefined = module.instance.exports.memory; 119 | ``` 120 | 121 | ### ✌️ License 122 | [__MIT__](LICENSE) 123 | -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9.0) 2 | 3 | set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build) 4 | set(CMAKE_VERBOSE_MAKEFILE ON) 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | find_library(log-lib log) 8 | 9 | add_library(cpp 10 | SHARED 11 | ../cpp/react-native-webassembly.cpp 12 | cpp-adapter.cpp 13 | # wasm3 14 | ../cpp/m3_api_libc.c 15 | ../cpp/m3_api_libc.h 16 | ../cpp/m3_api_meta_wasi.c 17 | ../cpp/m3_api_tracer.c 18 | ../cpp/m3_api_tracer.h 19 | ../cpp/m3_api_uvwasi.c 20 | ../cpp/m3_api_wasi.c 21 | ../cpp/m3_api_wasi.h 22 | ../cpp/m3_bind.c 23 | ../cpp/m3_bind.h 24 | ../cpp/m3_code.c 25 | ../cpp/m3_code.h 26 | ../cpp/m3_compile.c 27 | ../cpp/m3_compile.h 28 | ../cpp/m3_config.h 29 | ../cpp/m3_config_platforms.h 30 | ../cpp/m3_core.c 31 | ../cpp/m3_core.h 32 | ../cpp/m3_env.c 33 | ../cpp/m3_env.h 34 | ../cpp/m3_exception.h 35 | ../cpp/m3_exec.c 36 | ../cpp/m3_exec.h 37 | ../cpp/m3_exec_defs.h 38 | ../cpp/m3_function.c 39 | ../cpp/m3_function.h 40 | ../cpp/m3_info.c 41 | ../cpp/m3_info.h 42 | ../cpp/m3_math_utils.h 43 | ../cpp/m3_module.c 44 | ../cpp/m3_parse.c 45 | ../cpp/react-native-webassembly.h 46 | ../cpp/wasm3.h 47 | ../cpp/wasm3_cpp.h 48 | ../cpp/wasm3_defs.h 49 | ) 50 | 51 | # Specifies a path to native header files. 52 | include_directories( 53 | ../cpp 54 | ) 55 | 56 | set_target_properties( 57 | cpp PROPERTIES 58 | CXX_STANDARD 17 59 | CXX_EXTENSIONS OFF 60 | POSITION_INDEPENDENT_CODE ON 61 | ) 62 | 63 | find_package(ReactAndroid REQUIRED CONFIG) 64 | 65 | target_link_libraries( 66 | cpp 67 | ${log-lib} 68 | ReactAndroid::jsi 69 | android 70 | ) 71 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:7.2.1" 9 | } 10 | } 11 | 12 | def isNewArchitectureEnabled() { 13 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 14 | } 15 | 16 | apply plugin: "com.android.library" 17 | 18 | 19 | def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } 20 | 21 | if (isNewArchitectureEnabled()) { 22 | apply plugin: "com.facebook.react" 23 | } 24 | 25 | def getExtOrDefault(name) { 26 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Webassembly_" + name] 27 | } 28 | 29 | def getExtOrIntegerDefault(name) { 30 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Webassembly_" + name]).toInteger() 31 | } 32 | 33 | android { 34 | ndkVersion getExtOrDefault("ndkVersion") 35 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 36 | namespace("com.webassembly") 37 | 38 | defaultConfig { 39 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 40 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 41 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 42 | externalNativeBuild { 43 | cmake { 44 | cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all" 45 | arguments "-DANDROID_STL=c++_shared" 46 | abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a" 47 | } 48 | } 49 | } 50 | externalNativeBuild { 51 | cmake { 52 | path "CMakeLists.txt" 53 | } 54 | } 55 | buildTypes { 56 | release { 57 | minifyEnabled false 58 | } 59 | } 60 | 61 | buildFeatures { 62 | prefab true 63 | } 64 | 65 | lintOptions { 66 | disable "GradleCompatible" 67 | } 68 | 69 | compileOptions { 70 | sourceCompatibility JavaVersion.VERSION_1_8 71 | targetCompatibility JavaVersion.VERSION_1_8 72 | } 73 | 74 | sourceSets { 75 | main { 76 | if (isNewArchitectureEnabled()) { 77 | java.srcDirs += [ 78 | // This is needed to build Kotlin project with NewArch enabled 79 | "${project.buildDir}/generated/source/codegen/java" 80 | ] 81 | } 82 | } 83 | } 84 | } 85 | 86 | repositories { 87 | mavenCentral() 88 | google() 89 | } 90 | 91 | 92 | dependencies { 93 | // For < 0.71, this will be from the local maven repo 94 | // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin 95 | //noinspection GradleDynamicVersion 96 | implementation "com.facebook.react:react-native:+" 97 | } 98 | 99 | if (isNewArchitectureEnabled()) { 100 | react { 101 | jsRootDir = file("../src/") 102 | libraryName = "Webassembly" 103 | codegenJavaPackageName = "com.webassembly" 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /android/cpp-adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "react-native-webassembly.h" 6 | 7 | 8 | using namespace facebook::jsi; 9 | using namespace std; 10 | 11 | extern "C" 12 | JNIEXPORT void JNICALL 13 | Java_com_webassembly_WebassemblyModule_nativeInstall(JNIEnv *env, jobject thiz, jlong jsi) { 14 | 15 | auto runtime = reinterpret_cast(jsi); 16 | 17 | if (runtime) { 18 | webassembly::install(*runtime); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | Webassembly_kotlinVersion=1.7.0 2 | Webassembly_minSdkVersion=21 3 | Webassembly_targetSdkVersion=31 4 | Webassembly_compileSdkVersion=31 5 | Webassembly_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/java/com/webassembly/WebassemblyModule.java: -------------------------------------------------------------------------------- 1 | package com.webassembly; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.bridge.ReactMethod; 8 | import com.facebook.react.module.annotations.ReactModule; 9 | 10 | @ReactModule(name = WebassemblyModule.NAME) 11 | public class WebassemblyModule extends ReactContextBaseJavaModule { 12 | public static final String NAME = "Webassembly"; 13 | 14 | private native void nativeInstall(long jsiPtr, String docDir); 15 | 16 | public WebassemblyModule(ReactApplicationContext reactContext) { 17 | super(reactContext); 18 | } 19 | 20 | @Override 21 | @NonNull 22 | public String getName() { 23 | return NAME; 24 | } 25 | 26 | @ReactMethod(isBlockingSynchronousMethod = true) 27 | public boolean install() { 28 | try { 29 | System.loadLibrary("cpp"); 30 | 31 | ReactApplicationContext context = getReactApplicationContext(); 32 | nativeInstall( 33 | context.getJavaScriptContextHolder().get(), 34 | context.getFilesDir().getAbsolutePath() 35 | ); 36 | return true; 37 | } catch (Exception exception) { 38 | return false; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /android/src/main/java/com/webassembly/WebassemblyPackage.java: -------------------------------------------------------------------------------- 1 | package com.webassembly; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.uimanager.ViewManager; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class WebassemblyPackage implements ReactPackage { 14 | @NonNull 15 | @Override 16 | public List createNativeModules(@NonNull ReactApplicationContext reactContext) { 17 | return Collections.singletonList(new WebassemblyModule(reactContext)); 18 | } 19 | 20 | @NonNull 21 | @Override 22 | public List createViewManagers(@NonNull ReactApplicationContext reactContext) { 23 | return Collections.emptyList(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app.plugin.js: -------------------------------------------------------------------------------- 1 | const { 2 | withPlugins, 3 | AndroidConfig, 4 | createRunOncePlugin, 5 | } = require('@expo/config-plugins'); 6 | 7 | const { name, version } = require('./package.json'); 8 | 9 | const withWebAssembly = (config) => { 10 | if (!config.ios) config.ios = {}; 11 | if (!config.ios.infoPlist) config.ios.infoPlist = {}; 12 | 13 | const androidPermissions = []; 14 | 15 | return withPlugins(config, [ 16 | [AndroidConfig.Permissions.withPermissions, androidPermissions], 17 | ]); 18 | }; 19 | 20 | module.exports = createRunOncePlugin(withWebAssembly, name, version); 21 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /cpp/m3_api_libc.c: -------------------------------------------------------------------------------- 1 | // 2 | // m3_api_libc.c 3 | // 4 | // Created by Volodymyr Shymanskyy on 11/20/19. 5 | // Copyright © 2019 Volodymyr Shymanskyy. All rights reserved. 6 | // 7 | 8 | #define _POSIX_C_SOURCE 200809L 9 | 10 | #include "m3_api_libc.h" 11 | 12 | #include "m3_env.h" 13 | #include "m3_exception.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | typedef uint32_t wasm_ptr_t; 20 | typedef uint32_t wasm_size_t; 21 | 22 | m3ApiRawFunction(m3_libc_abort) 23 | { 24 | m3ApiTrap(m3Err_trapAbort); 25 | } 26 | 27 | m3ApiRawFunction(m3_libc_exit) 28 | { 29 | m3ApiGetArg (int32_t, code) 30 | 31 | m3ApiTrap(m3Err_trapExit); 32 | } 33 | 34 | 35 | m3ApiRawFunction(m3_libc_memset) 36 | { 37 | m3ApiReturnType (int32_t) 38 | 39 | m3ApiGetArgMem (void*, i_ptr) 40 | m3ApiGetArg (int32_t, i_value) 41 | m3ApiGetArg (wasm_size_t, i_size) 42 | 43 | m3ApiCheckMem(i_ptr, i_size); 44 | 45 | u32 result = m3ApiPtrToOffset(memset (i_ptr, i_value, i_size)); 46 | m3ApiReturn(result); 47 | } 48 | 49 | m3ApiRawFunction(m3_libc_memmove) 50 | { 51 | m3ApiReturnType (int32_t) 52 | 53 | m3ApiGetArgMem (void*, o_dst) 54 | m3ApiGetArgMem (void*, i_src) 55 | m3ApiGetArg (wasm_size_t, i_size) 56 | 57 | m3ApiCheckMem(o_dst, i_size); 58 | m3ApiCheckMem(i_src, i_size); 59 | 60 | u32 result = m3ApiPtrToOffset(memmove (o_dst, i_src, i_size)); 61 | m3ApiReturn(result); 62 | } 63 | 64 | m3ApiRawFunction(m3_libc_print) 65 | { 66 | m3ApiReturnType (uint32_t) 67 | 68 | m3ApiGetArgMem (void*, i_ptr) 69 | m3ApiGetArg (wasm_size_t, i_size) 70 | 71 | m3ApiCheckMem(i_ptr, i_size); 72 | 73 | fwrite(i_ptr, i_size, 1, stdout); 74 | fflush(stdout); 75 | 76 | m3ApiReturn(i_size); 77 | } 78 | 79 | static 80 | void internal_itoa(int n, char s[], int radix) 81 | { 82 | static char const HEXDIGITS[0x10] = { 83 | '0', '1', '2', '3', '4', '5', '6', '7', 84 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 85 | }; 86 | 87 | int i, j, sign; 88 | char c; 89 | 90 | if ((sign = n) < 0) { n = -n; } 91 | i = 0; 92 | do { 93 | s[i++] = HEXDIGITS[n % radix]; 94 | } while ((n /= radix) > 0); 95 | 96 | if (sign < 0) { s[i++] = '-'; } 97 | s[i] = '\0'; 98 | 99 | // reverse 100 | for (i = 0, j = strlen(s)-1; i d_m3MaxSaneFunctionArgRetCount); 46 | 47 | _ (AllocFuncType (& funcType, (u32) maxNumTypes)); 48 | 49 | u8 * typelist = funcType->types; 50 | 51 | bool parsingRets = true; 52 | while (* sig) 53 | { 54 | char typeChar = * sig++; 55 | 56 | if (typeChar == '(') 57 | { 58 | parsingRets = false; 59 | continue; 60 | } 61 | else if ( typeChar == ' ') 62 | continue; 63 | else if (typeChar == ')') 64 | break; 65 | 66 | u8 type = ConvertTypeCharToTypeId (typeChar); 67 | 68 | _throwif ("unknown argument type char", c_m3Type_unknown == type); 69 | 70 | if (type == c_m3Type_none) 71 | continue; 72 | 73 | if (parsingRets) 74 | { 75 | _throwif ("malformed signature; return count overflow", funcType->numRets >= maxNumTypes); 76 | funcType->numRets++; 77 | *typelist++ = type; 78 | } 79 | else 80 | { 81 | _throwif ("malformed signature; arg count overflow", (u32)(funcType->numRets) + funcType->numArgs >= maxNumTypes); 82 | funcType->numArgs++; 83 | *typelist++ = type; 84 | } 85 | } 86 | 87 | } _catch: 88 | 89 | if (result) 90 | m3_Free (funcType); 91 | 92 | * o_functionType = funcType; 93 | 94 | return result; 95 | } 96 | 97 | 98 | static 99 | M3Result ValidateSignature (IM3Function i_function, ccstr_t i_linkingSignature) 100 | { 101 | M3Result result = m3Err_none; 102 | 103 | IM3FuncType ftype = NULL; 104 | _ (SignatureToFuncType (& ftype, i_linkingSignature)); 105 | 106 | if (not AreFuncTypesEqual (ftype, i_function->funcType)) 107 | { 108 | m3log (module, "expected: %s", SPrintFuncTypeSignature (ftype)); 109 | m3log (module, " found: %s", SPrintFuncTypeSignature (i_function->funcType)); 110 | 111 | _throw ("function signature mismatch"); 112 | } 113 | 114 | _catch: 115 | 116 | m3_Free (ftype); 117 | 118 | return result; 119 | } 120 | 121 | 122 | M3Result FindAndLinkFunction (IM3Module io_module, 123 | ccstr_t i_moduleName, 124 | ccstr_t i_functionName, 125 | ccstr_t i_signature, 126 | voidptr_t i_function, 127 | voidptr_t i_userdata) 128 | { 129 | _try { 130 | 131 | _throwif(m3Err_moduleNotLinked, !io_module->runtime); 132 | 133 | const bool wildcardModule = (strcmp (i_moduleName, "*") == 0); 134 | 135 | result = m3Err_functionLookupFailed; 136 | 137 | for (u32 i = 0; i < io_module->numFunctions; ++i) 138 | { 139 | const IM3Function f = & io_module->functions [i]; 140 | 141 | if (f->import.moduleUtf8 and f->import.fieldUtf8) 142 | { 143 | if (strcmp (f->import.fieldUtf8, i_functionName) == 0 and 144 | (wildcardModule or strcmp (f->import.moduleUtf8, i_moduleName) == 0)) 145 | { 146 | if (i_signature) { 147 | _ (ValidateSignature (f, i_signature)); 148 | } 149 | _ (CompileRawFunction (io_module, f, i_function, i_userdata)); 150 | } 151 | } 152 | } 153 | } _catch: 154 | return result; 155 | } 156 | 157 | M3Result m3_LinkRawFunctionEx (IM3Module io_module, 158 | const char * const i_moduleName, 159 | const char * const i_functionName, 160 | const char * const i_signature, 161 | M3RawCall i_function, 162 | const void * i_userdata) 163 | { 164 | return FindAndLinkFunction (io_module, i_moduleName, i_functionName, i_signature, (voidptr_t)i_function, i_userdata); 165 | } 166 | 167 | M3Result m3_LinkRawFunction (IM3Module io_module, 168 | const char * const i_moduleName, 169 | const char * const i_functionName, 170 | const char * const i_signature, 171 | M3RawCall i_function) 172 | { 173 | return FindAndLinkFunction (io_module, i_moduleName, i_functionName, i_signature, (voidptr_t)i_function, NULL); 174 | } 175 | 176 | -------------------------------------------------------------------------------- /cpp/m3_bind.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_bind.h 3 | // 4 | // Created by Steven Massey on 2/27/20. 5 | // Copyright © 2020 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_bind_h 9 | #define m3_bind_h 10 | 11 | #include "m3_env.h" 12 | 13 | d_m3BeginExternC 14 | 15 | u8 ConvertTypeCharToTypeId (char i_code); 16 | char ConvertTypeIdToTypeChar (u8 type); 17 | M3Result SignatureToFuncType (IM3FuncType * o_functionType, ccstr_t i_signature); 18 | 19 | d_m3EndExternC 20 | 21 | #endif /* m3_bind_h */ 22 | -------------------------------------------------------------------------------- /cpp/m3_code.c: -------------------------------------------------------------------------------- 1 | // 2 | // m3_code.c 3 | // 4 | // Created by Steven Massey on 4/19/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #include 9 | #include "m3_code.h" 10 | #include "m3_env.h" 11 | 12 | //--------------------------------------------------------------------------------------------------------------------------------- 13 | 14 | 15 | IM3CodePage NewCodePage (IM3Runtime i_runtime, u32 i_minNumLines) 16 | { 17 | IM3CodePage page; 18 | 19 | // check multiplication overflow 20 | if (i_minNumLines > UINT_MAX / sizeof (code_t)) { 21 | return NULL; 22 | } 23 | u32 pageSize = sizeof (M3CodePageHeader) + sizeof (code_t) * i_minNumLines; 24 | 25 | // check addition overflow 26 | if (pageSize < sizeof (M3CodePageHeader)) { 27 | return NULL; 28 | } 29 | 30 | pageSize = (pageSize + (d_m3CodePageAlignSize-1)) & ~(d_m3CodePageAlignSize-1); // align 31 | // check alignment overflow 32 | if (pageSize == 0) { 33 | return NULL; 34 | } 35 | 36 | page = (IM3CodePage)m3_Malloc ("M3CodePage", pageSize); 37 | 38 | if (page) 39 | { 40 | page->info.sequence = ++i_runtime->newCodePageSequence; 41 | page->info.numLines = (pageSize - sizeof (M3CodePageHeader)) / sizeof (code_t); 42 | 43 | #if d_m3RecordBacktraces 44 | u32 pageSizeBt = sizeof (M3CodeMappingPage) + sizeof (M3CodeMapEntry) * page->info.numLines; 45 | page->info.mapping = (M3CodeMappingPage *)m3_Malloc ("M3CodeMappingPage", pageSizeBt); 46 | 47 | if (page->info.mapping) 48 | { 49 | page->info.mapping->size = 0; 50 | page->info.mapping->capacity = page->info.numLines; 51 | } 52 | else 53 | { 54 | m3_Free (page); 55 | return NULL; 56 | } 57 | page->info.mapping->basePC = GetPageStartPC(page); 58 | #endif // d_m3RecordBacktraces 59 | 60 | m3log (runtime, "new page: %p; seq: %d; bytes: %d; lines: %d", GetPagePC (page), page->info.sequence, pageSize, page->info.numLines); 61 | } 62 | 63 | return page; 64 | } 65 | 66 | 67 | void FreeCodePages (IM3CodePage * io_list) 68 | { 69 | IM3CodePage page = * io_list; 70 | 71 | while (page) 72 | { 73 | m3log (code, "free page: %d; %p; util: %3.1f%%", page->info.sequence, page, 100. * page->info.lineIndex / page->info.numLines); 74 | 75 | IM3CodePage next = page->info.next; 76 | #if d_m3RecordBacktraces 77 | m3_Free (page->info.mapping); 78 | #endif // d_m3RecordBacktraces 79 | m3_Free (page); 80 | page = next; 81 | } 82 | 83 | * io_list = NULL; 84 | } 85 | 86 | 87 | u32 NumFreeLines (IM3CodePage i_page) 88 | { 89 | d_m3Assert (i_page->info.lineIndex <= i_page->info.numLines); 90 | 91 | return i_page->info.numLines - i_page->info.lineIndex; 92 | } 93 | 94 | 95 | void EmitWord_impl (IM3CodePage i_page, void * i_word) 96 | { d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines); 97 | i_page->code [i_page->info.lineIndex++] = i_word; 98 | } 99 | 100 | void EmitWord32 (IM3CodePage i_page, const u32 i_word) 101 | { d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines); 102 | memcpy (& i_page->code[i_page->info.lineIndex++], & i_word, sizeof(i_word)); 103 | } 104 | 105 | void EmitWord64 (IM3CodePage i_page, const u64 i_word) 106 | { 107 | #if M3_SIZEOF_PTR == 4 108 | d_m3Assert (i_page->info.lineIndex+2 <= i_page->info.numLines); 109 | memcpy (& i_page->code[i_page->info.lineIndex], & i_word, sizeof(i_word)); 110 | i_page->info.lineIndex += 2; 111 | #else 112 | d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines); 113 | memcpy (& i_page->code[i_page->info.lineIndex], & i_word, sizeof(i_word)); 114 | i_page->info.lineIndex += 1; 115 | #endif 116 | } 117 | 118 | 119 | #if d_m3RecordBacktraces 120 | void EmitMappingEntry (IM3CodePage i_page, u32 i_moduleOffset) 121 | { 122 | M3CodeMappingPage * page = i_page->info.mapping; 123 | d_m3Assert (page->size < page->capacity); 124 | 125 | M3CodeMapEntry * entry = & page->entries[page->size++]; 126 | pc_t pc = GetPagePC (i_page); 127 | 128 | entry->pcOffset = pc - page->basePC; 129 | entry->moduleOffset = i_moduleOffset; 130 | } 131 | #endif // d_m3RecordBacktraces 132 | 133 | pc_t GetPageStartPC (IM3CodePage i_page) 134 | { 135 | return & i_page->code [0]; 136 | } 137 | 138 | 139 | pc_t GetPagePC (IM3CodePage i_page) 140 | { 141 | if (i_page) 142 | return & i_page->code [i_page->info.lineIndex]; 143 | else 144 | return NULL; 145 | } 146 | 147 | 148 | void PushCodePage (IM3CodePage * i_list, IM3CodePage i_codePage) 149 | { 150 | IM3CodePage next = * i_list; 151 | i_codePage->info.next = next; 152 | * i_list = i_codePage; 153 | } 154 | 155 | 156 | IM3CodePage PopCodePage (IM3CodePage * i_list) 157 | { 158 | IM3CodePage page = * i_list; 159 | * i_list = page->info.next; 160 | page->info.next = NULL; 161 | 162 | return page; 163 | } 164 | 165 | 166 | 167 | u32 FindCodePageEnd (IM3CodePage i_list, IM3CodePage * o_end) 168 | { 169 | u32 numPages = 0; 170 | * o_end = NULL; 171 | 172 | while (i_list) 173 | { 174 | * o_end = i_list; 175 | ++numPages; 176 | i_list = i_list->info.next; 177 | } 178 | 179 | return numPages; 180 | } 181 | 182 | 183 | u32 CountCodePages (IM3CodePage i_list) 184 | { 185 | IM3CodePage unused; 186 | return FindCodePageEnd (i_list, & unused); 187 | } 188 | 189 | 190 | IM3CodePage GetEndCodePage (IM3CodePage i_list) 191 | { 192 | IM3CodePage end; 193 | FindCodePageEnd (i_list, & end); 194 | 195 | return end; 196 | } 197 | 198 | #if d_m3RecordBacktraces 199 | bool ContainsPC (IM3CodePage i_page, pc_t i_pc) 200 | { 201 | return GetPageStartPC (i_page) <= i_pc && i_pc < GetPagePC (i_page); 202 | } 203 | 204 | 205 | bool MapPCToOffset (IM3CodePage i_page, pc_t i_pc, u32 * o_moduleOffset) 206 | { 207 | M3CodeMappingPage * mapping = i_page->info.mapping; 208 | 209 | u32 pcOffset = i_pc - mapping->basePC; 210 | 211 | u32 left = 0; 212 | u32 right = mapping->size; 213 | 214 | while (left < right) 215 | { 216 | u32 mid = left + (right - left) / 2; 217 | 218 | if (mapping->entries[mid].pcOffset < pcOffset) 219 | { 220 | left = mid + 1; 221 | } 222 | else if (mapping->entries[mid].pcOffset > pcOffset) 223 | { 224 | right = mid; 225 | } 226 | else 227 | { 228 | *o_moduleOffset = mapping->entries[mid].moduleOffset; 229 | return true; 230 | } 231 | } 232 | 233 | // Getting here means left is now one more than the element we want. 234 | if (left > 0) 235 | { 236 | left--; 237 | *o_moduleOffset = mapping->entries[left].moduleOffset; 238 | return true; 239 | } 240 | else return false; 241 | } 242 | #endif // d_m3RecordBacktraces 243 | 244 | //--------------------------------------------------------------------------------------------------------------------------------- 245 | 246 | 247 | -------------------------------------------------------------------------------- /cpp/m3_code.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_code.h 3 | // 4 | // Created by Steven Massey on 4/19/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_code_h 9 | #define m3_code_h 10 | 11 | #include "m3_core.h" 12 | 13 | d_m3BeginExternC 14 | 15 | typedef struct M3CodePage 16 | { 17 | M3CodePageHeader info; 18 | code_t code [1]; 19 | } 20 | M3CodePage; 21 | 22 | typedef M3CodePage * IM3CodePage; 23 | 24 | 25 | IM3CodePage NewCodePage (IM3Runtime i_runtime, u32 i_minNumLines); 26 | 27 | void FreeCodePages (IM3CodePage * io_list); 28 | 29 | u32 NumFreeLines (IM3CodePage i_page); 30 | pc_t GetPageStartPC (IM3CodePage i_page); 31 | pc_t GetPagePC (IM3CodePage i_page); 32 | void EmitWord_impl (IM3CodePage i_page, void* i_word); 33 | void EmitWord32 (IM3CodePage i_page, u32 i_word); 34 | void EmitWord64 (IM3CodePage i_page, u64 i_word); 35 | # if d_m3RecordBacktraces 36 | void EmitMappingEntry (IM3CodePage i_page, u32 i_moduleOffset); 37 | # endif // d_m3RecordBacktraces 38 | 39 | void PushCodePage (IM3CodePage * io_list, IM3CodePage i_codePage); 40 | IM3CodePage PopCodePage (IM3CodePage * io_list); 41 | 42 | IM3CodePage GetEndCodePage (IM3CodePage i_list); // i_list = NULL is valid 43 | u32 CountCodePages (IM3CodePage i_list); // i_list = NULL is valid 44 | 45 | # if d_m3RecordBacktraces 46 | bool ContainsPC (IM3CodePage i_page, pc_t i_pc); 47 | bool MapPCToOffset (IM3CodePage i_page, pc_t i_pc, u32 * o_moduleOffset); 48 | # endif // d_m3RecordBacktraces 49 | 50 | # ifdef DEBUG 51 | void dump_code_page (IM3CodePage i_codePage, pc_t i_startPC); 52 | # endif 53 | 54 | #define EmitWord(page, val) EmitWord_impl(page, (void*)(val)) 55 | 56 | //--------------------------------------------------------------------------------------------------------------------------------- 57 | 58 | # if d_m3RecordBacktraces 59 | 60 | typedef struct M3CodeMapEntry 61 | { 62 | u32 pcOffset; 63 | u32 moduleOffset; 64 | } 65 | M3CodeMapEntry; 66 | 67 | typedef struct M3CodeMappingPage 68 | { 69 | pc_t basePC; 70 | u32 size; 71 | u32 capacity; 72 | M3CodeMapEntry entries []; 73 | } 74 | M3CodeMappingPage; 75 | 76 | # endif // d_m3RecordBacktraces 77 | 78 | d_m3EndExternC 79 | 80 | #endif // m3_code_h 81 | -------------------------------------------------------------------------------- /cpp/m3_compile.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_compile.h 3 | // 4 | // Created by Steven Massey on 4/17/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_compile_h 9 | #define m3_compile_h 10 | 11 | #include "m3_code.h" 12 | #include "m3_exec_defs.h" 13 | #include "m3_function.h" 14 | 15 | d_m3BeginExternC 16 | 17 | enum 18 | { 19 | c_waOp_block = 0x02, 20 | c_waOp_loop = 0x03, 21 | c_waOp_if = 0x04, 22 | c_waOp_else = 0x05, 23 | c_waOp_end = 0x0b, 24 | c_waOp_branch = 0x0c, 25 | c_waOp_branchTable = 0x0e, 26 | c_waOp_branchIf = 0x0d, 27 | c_waOp_call = 0x10, 28 | c_waOp_getLocal = 0x20, 29 | c_waOp_setLocal = 0x21, 30 | c_waOp_teeLocal = 0x22, 31 | 32 | c_waOp_getGlobal = 0x23, 33 | 34 | c_waOp_store_f32 = 0x38, 35 | c_waOp_store_f64 = 0x39, 36 | 37 | c_waOp_i32_const = 0x41, 38 | c_waOp_i64_const = 0x42, 39 | c_waOp_f32_const = 0x43, 40 | c_waOp_f64_const = 0x44, 41 | 42 | c_waOp_extended = 0xfc, 43 | 44 | c_waOp_memoryCopy = 0xfc0a, 45 | c_waOp_memoryFill = 0xfc0b 46 | }; 47 | 48 | 49 | #define d_FuncRetType(ftype,i) ((ftype)->types[(i)]) 50 | #define d_FuncArgType(ftype,i) ((ftype)->types[(ftype)->numRets + (i)]) 51 | 52 | //----------------------------------------------------------------------------------------------------------------------------------- 53 | 54 | typedef struct M3CompilationScope 55 | { 56 | struct M3CompilationScope * outer; 57 | 58 | pc_t pc; // used by ContinueLoop's 59 | pc_t patches; 60 | i32 depth; 61 | u16 exitStackIndex; 62 | u16 blockStackIndex; 63 | // u16 topSlot; 64 | IM3FuncType type; 65 | m3opcode_t opcode; 66 | bool isPolymorphic; 67 | } 68 | M3CompilationScope; 69 | 70 | typedef M3CompilationScope * IM3CompilationScope; 71 | 72 | typedef struct 73 | { 74 | IM3Runtime runtime; 75 | IM3Module module; 76 | 77 | bytes_t wasm; 78 | bytes_t wasmEnd; 79 | bytes_t lastOpcodeStart; 80 | 81 | M3CompilationScope block; 82 | 83 | IM3Function function; 84 | 85 | IM3CodePage page; 86 | 87 | #ifdef DEBUG 88 | u32 numEmits; 89 | u32 numOpcodes; 90 | #endif 91 | 92 | u16 stackFirstDynamicIndex; // args and locals are pushed to the stack so that their slot locations can be tracked. the wasm model itself doesn't 93 | // treat these values as being on the stack, so stackFirstDynamicIndex marks the start of the real Wasm stack 94 | u16 stackIndex; // current stack top 95 | 96 | u16 slotFirstConstIndex; 97 | u16 slotMaxConstIndex; // as const's are encountered during compilation this tracks their location in the "real" stack 98 | 99 | u16 slotFirstLocalIndex; 100 | u16 slotFirstDynamicIndex; // numArgs + numLocals + numReservedConstants. the first mutable slot available to the compiler. 101 | 102 | u16 maxStackSlots; 103 | 104 | m3slot_t constants [d_m3MaxConstantTableSize]; 105 | 106 | // 'wasmStack' holds slot locations 107 | u16 wasmStack [d_m3MaxFunctionStackHeight]; 108 | u8 typeStack [d_m3MaxFunctionStackHeight]; 109 | 110 | // 'm3Slots' contains allocation usage counts 111 | u8 m3Slots [d_m3MaxFunctionSlots]; 112 | 113 | u16 slotMaxAllocatedIndexPlusOne; 114 | 115 | u16 regStackIndexPlusOne [2]; 116 | 117 | m3opcode_t previousOpcode; 118 | } 119 | M3Compilation; 120 | 121 | typedef M3Compilation * IM3Compilation; 122 | 123 | typedef M3Result (* M3Compiler) (IM3Compilation, m3opcode_t); 124 | 125 | 126 | //----------------------------------------------------------------------------------------------------------------------------------- 127 | 128 | 129 | typedef struct M3OpInfo 130 | { 131 | #ifdef DEBUG 132 | const char * const name; 133 | #endif 134 | 135 | i8 stackOffset; 136 | u8 type; 137 | 138 | // for most operations: 139 | // [0]= top operand in register, [1]= top operand in stack, [2]= both operands in stack 140 | IM3Operation operations [4]; 141 | 142 | M3Compiler compiler; 143 | } 144 | M3OpInfo; 145 | 146 | typedef const M3OpInfo * IM3OpInfo; 147 | 148 | IM3OpInfo GetOpInfo (m3opcode_t opcode); 149 | 150 | // TODO: This helper should be removed, when MultiValue is implemented 151 | static inline 152 | u8 GetSingleRetType(IM3FuncType ftype) { 153 | return (ftype && ftype->numRets) ? ftype->types[0] : (u8)c_m3Type_none; 154 | } 155 | 156 | static const u16 c_m3RegisterUnallocated = 0; 157 | static const u16 c_slotUnused = 0xffff; 158 | 159 | static inline 160 | bool IsRegisterAllocated (IM3Compilation o, u32 i_register) 161 | { 162 | return (o->regStackIndexPlusOne [i_register] != c_m3RegisterUnallocated); 163 | } 164 | 165 | static inline 166 | bool IsStackPolymorphic (IM3Compilation o) 167 | { 168 | return o->block.isPolymorphic; 169 | } 170 | 171 | static inline bool IsRegisterSlotAlias (u16 i_slot) { return (i_slot >= d_m3Reg0SlotAlias and i_slot != c_slotUnused); } 172 | static inline bool IsFpRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Fp0SlotAlias); } 173 | static inline bool IsIntRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Reg0SlotAlias); } 174 | 175 | 176 | #ifdef DEBUG 177 | #define M3OP(...) { __VA_ARGS__ } 178 | #define M3OP_RESERVED { "reserved" } 179 | #else 180 | // Strip-off name 181 | #define M3OP(name, ...) { __VA_ARGS__ } 182 | #define M3OP_RESERVED { 0 } 183 | #endif 184 | 185 | #if d_m3HasFloat 186 | #define M3OP_F M3OP 187 | #elif d_m3NoFloatDynamic 188 | #define M3OP_F(n,o,t,op,...) M3OP(n, o, t, { op_Unsupported, op_Unsupported, op_Unsupported, op_Unsupported }, __VA_ARGS__) 189 | #else 190 | #define M3OP_F(...) { 0 } 191 | #endif 192 | 193 | //----------------------------------------------------------------------------------------------------------------------------------- 194 | 195 | u16 GetMaxUsedSlotPlusOne (IM3Compilation o); 196 | 197 | M3Result CompileBlock (IM3Compilation io, IM3FuncType i_blockType, m3opcode_t i_blockOpcode); 198 | 199 | M3Result CompileBlockStatements (IM3Compilation io); 200 | M3Result CompileFunction (IM3Function io_function); 201 | 202 | M3Result CompileRawFunction (IM3Module io_module, IM3Function io_function, const void * i_function, const void * i_userdata); 203 | 204 | d_m3EndExternC 205 | 206 | #endif // m3_compile_h 207 | -------------------------------------------------------------------------------- /cpp/m3_config.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_config.h 3 | // 4 | // Created by Steven Massey on 5/4/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_config_h 9 | #define m3_config_h 10 | 11 | #include "m3_config_platforms.h" 12 | 13 | // general -------------------------------------------------------------------- 14 | 15 | # ifndef d_m3CodePageAlignSize 16 | # define d_m3CodePageAlignSize 32*1024 17 | # endif 18 | 19 | # ifndef d_m3MaxFunctionStackHeight 20 | # define d_m3MaxFunctionStackHeight 2000 // max: 32768 21 | # endif 22 | 23 | # ifndef d_m3MaxLinearMemoryPages 24 | # define d_m3MaxLinearMemoryPages 65536 25 | # endif 26 | 27 | # ifndef d_m3MaxFunctionSlots 28 | # define d_m3MaxFunctionSlots ((d_m3MaxFunctionStackHeight)*2) 29 | # endif 30 | 31 | # ifndef d_m3MaxConstantTableSize 32 | # define d_m3MaxConstantTableSize 120 33 | # endif 34 | 35 | # ifndef d_m3MaxDuplicateFunctionImpl 36 | # define d_m3MaxDuplicateFunctionImpl 3 37 | # endif 38 | 39 | # ifndef d_m3CascadedOpcodes // Cascaded opcodes are slightly faster at the expense of some memory 40 | # define d_m3CascadedOpcodes 1 // Adds ~3Kb to operations table in m3_compile.c 41 | # endif 42 | 43 | # ifndef d_m3VerboseErrorMessages 44 | # define d_m3VerboseErrorMessages 1 45 | # endif 46 | 47 | # ifndef d_m3FixedHeap 48 | # define d_m3FixedHeap false 49 | //# define d_m3FixedHeap (32*1024) 50 | # endif 51 | 52 | # ifndef d_m3FixedHeapAlign 53 | # define d_m3FixedHeapAlign 16 54 | # endif 55 | 56 | # ifndef d_m3Use32BitSlots 57 | # define d_m3Use32BitSlots 1 58 | # endif 59 | 60 | # ifndef d_m3ProfilerSlotMask 61 | # define d_m3ProfilerSlotMask 0xFFFF 62 | # endif 63 | 64 | # ifndef d_m3RecordBacktraces 65 | # define d_m3RecordBacktraces 0 66 | # endif 67 | 68 | # ifndef d_m3EnableExceptionBreakpoint 69 | # define d_m3EnableExceptionBreakpoint 0 // see m3_exception.h 70 | # endif 71 | 72 | 73 | // profiling and tracing ------------------------------------------------------ 74 | 75 | # ifndef d_m3EnableOpProfiling 76 | # define d_m3EnableOpProfiling 0 // opcode usage counters 77 | # endif 78 | 79 | # ifndef d_m3EnableOpTracing 80 | # define d_m3EnableOpTracing 0 // only works with DEBUG 81 | # endif 82 | 83 | # ifndef d_m3EnableWasiTracing 84 | # define d_m3EnableWasiTracing 0 85 | # endif 86 | 87 | # ifndef d_m3EnableStrace 88 | # define d_m3EnableStrace 0 // 1 - trace exported function calls 89 | // 2 - trace all calls (structured) 90 | // 3 - all calls + loops + memory operations 91 | # endif 92 | 93 | 94 | // logging -------------------------------------------------------------------- 95 | 96 | # ifndef d_m3LogParse 97 | # define d_m3LogParse 0 // .wasm binary decoding info 98 | # endif 99 | 100 | # ifndef d_m3LogModule 101 | # define d_m3LogModule 0 // wasm module info 102 | # endif 103 | 104 | # ifndef d_m3LogCompile 105 | # define d_m3LogCompile 0 // wasm -> metacode generation phase 106 | # endif 107 | 108 | # ifndef d_m3LogWasmStack 109 | # define d_m3LogWasmStack 0 // dump the wasm stack when pushed or popped 110 | # endif 111 | 112 | # ifndef d_m3LogEmit 113 | # define d_m3LogEmit 0 // metacode generation info 114 | # endif 115 | 116 | # ifndef d_m3LogCodePages 117 | # define d_m3LogCodePages 0 // dump metacode pages when released 118 | # endif 119 | 120 | # ifndef d_m3LogRuntime 121 | # define d_m3LogRuntime 0 // higher-level runtime information 122 | # endif 123 | 124 | # ifndef d_m3LogNativeStack 125 | # define d_m3LogNativeStack 0 // track the memory usage of the C-stack 126 | # endif 127 | 128 | # ifndef d_m3LogHeapOps 129 | # define d_m3LogHeapOps 0 // track heap usage 130 | # endif 131 | 132 | # ifndef d_m3LogTimestamps 133 | # define d_m3LogTimestamps 0 // track timestamps on heap logs 134 | # endif 135 | 136 | // other ---------------------------------------------------------------------- 137 | 138 | # ifndef d_m3HasFloat 139 | # define d_m3HasFloat 1 // implement floating point ops 140 | # endif 141 | 142 | #if !d_m3HasFloat && !defined(d_m3NoFloatDynamic) 143 | # define d_m3NoFloatDynamic 1 // if no floats, do not fail until flops are actually executed 144 | #endif 145 | 146 | # ifndef d_m3SkipStackCheck 147 | # define d_m3SkipStackCheck 0 // skip stack overrun checks 148 | # endif 149 | 150 | # ifndef d_m3SkipMemoryBoundsCheck 151 | # define d_m3SkipMemoryBoundsCheck 0 // skip memory bounds checks 152 | # endif 153 | 154 | #define d_m3EnableCodePageRefCounting 0 // not supported currently 155 | 156 | #endif // m3_config_h 157 | -------------------------------------------------------------------------------- /cpp/m3_config_platforms.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_config_platforms.h 3 | // 4 | // Created by Volodymyr Shymanskyy on 11/20/19. 5 | // Copyright © 2019 Volodymyr Shymanskyy. All rights reserved. 6 | // 7 | 8 | #ifndef m3_config_platforms_h 9 | #define m3_config_platforms_h 10 | 11 | #include "wasm3_defs.h" 12 | 13 | /* 14 | * Internal helpers 15 | */ 16 | 17 | # if !defined(__cplusplus) || defined(_MSC_VER) 18 | # define not ! 19 | # define and && 20 | # define or || 21 | # endif 22 | 23 | /* 24 | * Detect/define features 25 | */ 26 | 27 | # if defined(M3_COMPILER_MSVC) 28 | # include 29 | # if UINTPTR_MAX == 0xFFFFFFFF 30 | # define M3_SIZEOF_PTR 4 31 | # elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu 32 | # define M3_SIZEOF_PTR 8 33 | # else 34 | # error "Pointer size not supported" 35 | # endif 36 | # elif defined(__SIZEOF_POINTER__) 37 | # define M3_SIZEOF_PTR __SIZEOF_POINTER__ 38 | #else 39 | # error "Pointer size not detected" 40 | # endif 41 | 42 | # if defined(M3_BIG_ENDIAN) 43 | # define M3_BSWAP_u8(X) {} 44 | # define M3_BSWAP_u16(X) { (X)=m3_bswap16((X)); } 45 | # define M3_BSWAP_u32(X) { (X)=m3_bswap32((X)); } 46 | # define M3_BSWAP_u64(X) { (X)=m3_bswap64((X)); } 47 | # define M3_BSWAP_i8(X) {} 48 | # define M3_BSWAP_i16(X) M3_BSWAP_u16(X) 49 | # define M3_BSWAP_i32(X) M3_BSWAP_u32(X) 50 | # define M3_BSWAP_i64(X) M3_BSWAP_u64(X) 51 | # define M3_BSWAP_f32(X) { union { f32 f; u32 i; } u; u.f = (X); M3_BSWAP_u32(u.i); (X) = u.f; } 52 | # define M3_BSWAP_f64(X) { union { f64 f; u64 i; } u; u.f = (X); M3_BSWAP_u64(u.i); (X) = u.f; } 53 | # else 54 | # define M3_BSWAP_u8(X) {} 55 | # define M3_BSWAP_u16(x) {} 56 | # define M3_BSWAP_u32(x) {} 57 | # define M3_BSWAP_u64(x) {} 58 | # define M3_BSWAP_i8(X) {} 59 | # define M3_BSWAP_i16(X) {} 60 | # define M3_BSWAP_i32(X) {} 61 | # define M3_BSWAP_i64(X) {} 62 | # define M3_BSWAP_f32(X) {} 63 | # define M3_BSWAP_f64(X) {} 64 | # endif 65 | 66 | # if defined(M3_COMPILER_MSVC) 67 | # define M3_WEAK //__declspec(selectany) 68 | # define M3_NO_UBSAN 69 | # define M3_NOINLINE 70 | # elif defined(__MINGW32__) || defined(__CYGWIN__) 71 | # define M3_WEAK //__attribute__((selectany)) 72 | # define M3_NO_UBSAN 73 | # define M3_NOINLINE __attribute__((noinline)) 74 | # else 75 | # define M3_WEAK __attribute__((weak)) 76 | # define M3_NO_UBSAN //__attribute__((no_sanitize("undefined"))) 77 | // Workaround for Cosmopolitan noinline conflict: https://github.com/jart/cosmopolitan/issues/310 78 | # if defined(noinline) 79 | # define M3_NOINLINE noinline 80 | # else 81 | # define M3_NOINLINE __attribute__((noinline)) 82 | # endif 83 | # endif 84 | 85 | # if M3_COMPILER_HAS_ATTRIBUTE(musttail) 86 | # define M3_MUSTTAIL __attribute__((musttail)) 87 | # else 88 | # define M3_MUSTTAIL 89 | # endif 90 | 91 | # ifndef M3_MIN 92 | # define M3_MIN(A,B) (((A) < (B)) ? (A) : (B)) 93 | # endif 94 | # ifndef M3_MAX 95 | # define M3_MAX(A,B) (((A) > (B)) ? (A) : (B)) 96 | # endif 97 | 98 | #define M3_INIT(field) memset(&field, 0, sizeof(field)) 99 | 100 | #define M3_COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 101 | 102 | #if defined(__AVR__) 103 | 104 | #include 105 | 106 | # define PRIu64 "llu" 107 | # define PRIi64 "lli" 108 | 109 | # define d_m3ShortTypesDefined 110 | typedef double f64; 111 | typedef float f32; 112 | typedef uint64_t u64; 113 | typedef int64_t i64; 114 | typedef uint32_t u32; 115 | typedef int32_t i32; 116 | typedef short unsigned u16; 117 | typedef short i16; 118 | typedef uint8_t u8; 119 | typedef int8_t i8; 120 | 121 | #endif 122 | 123 | /* 124 | * Apply settings 125 | */ 126 | 127 | # if defined (M3_COMPILER_MSVC) 128 | # define vectorcall // For MSVC, better not to specify any call convention 129 | # elif defined(__x86_64__) 130 | # define vectorcall 131 | //# elif defined(__riscv) && (__riscv_xlen == 64) 132 | //# define vectorcall 133 | # elif defined(__MINGW32__) 134 | # define vectorcall 135 | # elif defined(WIN32) 136 | # define vectorcall __vectorcall 137 | # elif defined (ESP8266) 138 | # include 139 | # define vectorcall //ICACHE_FLASH_ATTR 140 | # elif defined (ESP32) 141 | # if defined(M3_IN_IRAM) // the interpreter is in IRAM, attribute not needed 142 | # define vectorcall 143 | # else 144 | # include "esp_system.h" 145 | # define vectorcall IRAM_ATTR 146 | # endif 147 | # elif defined (FOMU) 148 | # define vectorcall __attribute__((section(".ramtext"))) 149 | # endif 150 | 151 | #ifndef vectorcall 152 | #define vectorcall 153 | #endif 154 | 155 | 156 | /* 157 | * Device-specific defaults 158 | */ 159 | 160 | # ifndef d_m3MaxFunctionStackHeight 161 | # if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_AMEBA) || defined(TEENSYDUINO) 162 | # define d_m3MaxFunctionStackHeight 256 163 | # endif 164 | # endif 165 | 166 | # ifndef d_m3FixedHeap 167 | # if defined(ARDUINO_AMEBA) 168 | # define d_m3FixedHeap (128*1024) 169 | # elif defined(BLUE_PILL) || defined(FOMU) 170 | # define d_m3FixedHeap (12*1024) 171 | # elif defined(ARDUINO_ARCH_ARC32) // Arduino 101 172 | # define d_m3FixedHeap (10*1024) 173 | # endif 174 | # endif 175 | 176 | /* 177 | * Platform-specific defaults 178 | */ 179 | 180 | # if defined(ARDUINO) || defined(PARTICLE) || defined(PLATFORMIO) || defined(__MBED__) || \ 181 | defined(ESP8266) || defined(ESP32) || defined(BLUE_PILL) || defined(WM_W600) || defined(FOMU) 182 | # ifndef d_m3CascadedOpcodes 183 | # define d_m3CascadedOpcodes 0 184 | # endif 185 | # ifndef d_m3VerboseErrorMessages 186 | # define d_m3VerboseErrorMessages 0 187 | # endif 188 | # ifndef d_m3MaxConstantTableSize 189 | # define d_m3MaxConstantTableSize 64 190 | # endif 191 | # ifndef d_m3MaxFunctionStackHeight 192 | # define d_m3MaxFunctionStackHeight 128 193 | # endif 194 | # ifndef d_m3CodePageAlignSize 195 | # define d_m3CodePageAlignSize 1024 196 | # endif 197 | # endif 198 | 199 | /* 200 | * Arch-specific defaults 201 | */ 202 | #if defined(__riscv) && (__riscv_xlen == 64) 203 | # ifndef d_m3Use32BitSlots 204 | # define d_m3Use32BitSlots 0 205 | # endif 206 | #endif 207 | 208 | #endif // m3_config_platforms_h 209 | -------------------------------------------------------------------------------- /cpp/m3_env.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_env.h 3 | // 4 | // Created by Steven Massey on 4/19/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_env_h 9 | #define m3_env_h 10 | 11 | #include "wasm3.h" 12 | #include "m3_code.h" 13 | #include "m3_compile.h" 14 | 15 | d_m3BeginExternC 16 | 17 | 18 | //--------------------------------------------------------------------------------------------------------------------------------- 19 | 20 | typedef struct M3MemoryInfo 21 | { 22 | u32 initPages; 23 | u32 maxPages; 24 | } 25 | M3MemoryInfo; 26 | 27 | 28 | typedef struct M3Memory 29 | { 30 | M3MemoryHeader * mallocated; 31 | 32 | u32 numPages; 33 | u32 maxPages; 34 | } 35 | M3Memory; 36 | 37 | typedef M3Memory * IM3Memory; 38 | 39 | 40 | //--------------------------------------------------------------------------------------------------------------------------------- 41 | 42 | typedef struct M3DataSegment 43 | { 44 | const u8 * initExpr; // wasm code 45 | const u8 * data; 46 | 47 | u32 initExprSize; 48 | u32 memoryRegion; 49 | u32 size; 50 | } 51 | M3DataSegment; 52 | 53 | //--------------------------------------------------------------------------------------------------------------------------------- 54 | 55 | typedef struct M3Global 56 | { 57 | M3ImportInfo import; 58 | 59 | union 60 | { 61 | i32 i32Value; 62 | i64 i64Value; 63 | #if d_m3HasFloat 64 | f64 f64Value; 65 | f32 f32Value; 66 | #endif 67 | }; 68 | 69 | cstr_t name; 70 | bytes_t initExpr; // wasm code 71 | u32 initExprSize; 72 | u8 type; 73 | bool imported; 74 | bool isMutable; 75 | } 76 | M3Global; 77 | 78 | 79 | //--------------------------------------------------------------------------------------------------------------------------------- 80 | typedef struct M3Module 81 | { 82 | struct M3Runtime * runtime; 83 | struct M3Environment * environment; 84 | 85 | bytes_t wasmStart; 86 | bytes_t wasmEnd; 87 | 88 | cstr_t name; 89 | 90 | u32 numFuncTypes; 91 | IM3FuncType * funcTypes; // array of pointers to list of FuncTypes 92 | 93 | u32 numFuncImports; 94 | u32 numFunctions; 95 | u32 allFunctions; // allocated functions count 96 | M3Function * functions; 97 | 98 | i32 startFunction; 99 | 100 | u32 numDataSegments; 101 | M3DataSegment * dataSegments; 102 | 103 | //u32 importedGlobals; 104 | u32 numGlobals; 105 | M3Global * globals; 106 | 107 | u32 numElementSegments; 108 | bytes_t elementSection; 109 | bytes_t elementSectionEnd; 110 | 111 | IM3Function * table0; 112 | u32 table0Size; 113 | 114 | M3MemoryInfo memoryInfo; 115 | bool memoryImported; 116 | 117 | //bool hasWasmCodeCopy; 118 | 119 | struct M3Module * next; 120 | } 121 | M3Module; 122 | 123 | M3Result Module_AddGlobal (IM3Module io_module, IM3Global * o_global, u8 i_type, bool i_mutable, bool i_isImported); 124 | 125 | M3Result Module_PreallocFunctions (IM3Module io_module, u32 i_totalFunctions); 126 | M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo /* can be null */); 127 | IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex); 128 | 129 | void Module_GenerateNames (IM3Module i_module); 130 | 131 | void FreeImportInfo (M3ImportInfo * i_info); 132 | 133 | //--------------------------------------------------------------------------------------------------------------------------------- 134 | 135 | typedef struct M3Environment 136 | { 137 | // struct M3Runtime * runtimes; 138 | 139 | IM3FuncType funcTypes; // linked list of unique M3FuncType structs that can be compared using pointer-equivalence 140 | 141 | IM3FuncType retFuncTypes [c_m3Type_unknown]; // these 'point' to elements in the linked list above. 142 | // the number of elements must match the basic types as per M3ValueType 143 | M3CodePage * pagesReleased; 144 | 145 | M3SectionHandler customSectionHandler; 146 | } 147 | M3Environment; 148 | 149 | void Environment_Release (IM3Environment i_environment); 150 | 151 | // takes ownership of io_funcType and returns a pointer to the persistent version (could be same or different) 152 | void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_funcType); 153 | 154 | //--------------------------------------------------------------------------------------------------------------------------------- 155 | 156 | typedef struct M3Runtime 157 | { 158 | M3Compilation compilation; 159 | 160 | IM3Environment environment; 161 | 162 | M3CodePage * pagesOpen; // linked list of code pages with writable space on them 163 | M3CodePage * pagesFull; // linked list of at-capacity pages 164 | 165 | u32 numCodePages; 166 | u32 numActiveCodePages; 167 | 168 | IM3Module modules; // linked list of imported modules 169 | 170 | void * stack; 171 | u32 stackSize; 172 | u32 numStackSlots; 173 | IM3Function lastCalled; // last function that successfully executed 174 | 175 | void * userdata; 176 | 177 | M3Memory memory; 178 | u32 memoryLimit; 179 | 180 | #if d_m3EnableStrace >= 2 181 | u32 callDepth; 182 | #endif 183 | 184 | M3ErrorInfo error; 185 | #if d_m3VerboseErrorMessages 186 | char error_message[256]; // the actual buffer. M3ErrorInfo can point to this 187 | #endif 188 | 189 | #if d_m3RecordBacktraces 190 | M3BacktraceInfo backtrace; 191 | #endif 192 | 193 | u32 newCodePageSequence; 194 | } 195 | M3Runtime; 196 | 197 | void InitRuntime (IM3Runtime io_runtime, u32 i_stackSizeInBytes); 198 | void Runtime_Release (IM3Runtime io_runtime); 199 | 200 | M3Result ResizeMemory (IM3Runtime io_runtime, u32 i_numPages); 201 | 202 | typedef void * (* ModuleVisitor) (IM3Module i_module, void * i_info); 203 | void * ForEachModule (IM3Runtime i_runtime, ModuleVisitor i_visitor, void * i_info); 204 | 205 | void * v_FindFunction (IM3Module i_module, const char * const i_name); 206 | 207 | IM3CodePage AcquireCodePage (IM3Runtime io_runtime); 208 | IM3CodePage AcquireCodePageWithCapacity (IM3Runtime io_runtime, u32 i_lineCount); 209 | void ReleaseCodePage (IM3Runtime io_runtime, IM3CodePage i_codePage); 210 | 211 | d_m3EndExternC 212 | 213 | #endif // m3_env_h 214 | -------------------------------------------------------------------------------- /cpp/m3_exception.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_exception.h 3 | // 4 | // Created by Steven Massey on 7/5/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | // some macros to emulate try/catch 8 | 9 | #ifndef m3_exception_h 10 | #define m3_exception_h 11 | 12 | #include "m3_config.h" 13 | 14 | # if d_m3EnableExceptionBreakpoint 15 | 16 | // declared in m3_info.c 17 | void ExceptionBreakpoint (cstr_t i_exception, cstr_t i_message); 18 | 19 | # define EXCEPTION_PRINT(ERROR) ExceptionBreakpoint (ERROR, (__FILE__ ":" M3_STR(__LINE__))) 20 | 21 | # else 22 | # define EXCEPTION_PRINT(...) 23 | # endif 24 | 25 | 26 | #define _try M3Result result = m3Err_none; 27 | #define _(TRY) { result = TRY; if (M3_UNLIKELY(result)) { EXCEPTION_PRINT (result); goto _catch; } } 28 | #define _throw(ERROR) { result = ERROR; EXCEPTION_PRINT (result); goto _catch; } 29 | #define _throwif(ERROR, COND) if (M3_UNLIKELY(COND)) { _throw(ERROR); } 30 | 31 | #define _throwifnull(PTR) _throwif (m3Err_mallocFailed, !(PTR)) 32 | 33 | #endif // m3_exception_h 34 | -------------------------------------------------------------------------------- /cpp/m3_exec.c: -------------------------------------------------------------------------------- 1 | // 2 | // m3_exec.c 3 | // 4 | // Created by Steven Massey on 4/17/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | // EMPTY FOR NOW 9 | -------------------------------------------------------------------------------- /cpp/m3_exec_defs.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_exec_defs.h 3 | // 4 | // Created by Steven Massey on 5/1/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_exec_defs_h 9 | #define m3_exec_defs_h 10 | 11 | #include "m3_core.h" 12 | 13 | d_m3BeginExternC 14 | 15 | # define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1) 16 | # define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime) 17 | # define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory)) 18 | 19 | # define d_m3BaseOpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0 20 | # define d_m3BaseOpArgs _sp, _mem, _r0 21 | # define d_m3BaseOpAllArgs _pc, _sp, _mem, _r0 22 | # define d_m3BaseOpDefaultArgs 0 23 | # define d_m3BaseClearRegisters _r0 = 0; 24 | 25 | # define d_m3ExpOpSig(...) d_m3BaseOpSig, __VA_ARGS__ 26 | # define d_m3ExpOpArgs(...) d_m3BaseOpArgs, __VA_ARGS__ 27 | # define d_m3ExpOpAllArgs(...) d_m3BaseOpAllArgs, __VA_ARGS__ 28 | # define d_m3ExpOpDefaultArgs(...) d_m3BaseOpDefaultArgs, __VA_ARGS__ 29 | # define d_m3ExpClearRegisters(...) d_m3BaseClearRegisters; __VA_ARGS__ 30 | 31 | # if d_m3HasFloat 32 | # define d_m3OpSig d_m3ExpOpSig (f64 _fp0) 33 | # define d_m3OpArgs d_m3ExpOpArgs (_fp0) 34 | # define d_m3OpAllArgs d_m3ExpOpAllArgs (_fp0) 35 | # define d_m3OpDefaultArgs d_m3ExpOpDefaultArgs (0.) 36 | # define d_m3ClearRegisters d_m3ExpClearRegisters (_fp0 = 0.;) 37 | # else 38 | # define d_m3OpSig d_m3BaseOpSig 39 | # define d_m3OpArgs d_m3BaseOpArgs 40 | # define d_m3OpAllArgs d_m3BaseOpAllArgs 41 | # define d_m3OpDefaultArgs d_m3BaseOpDefaultArgs 42 | # define d_m3ClearRegisters d_m3BaseClearRegisters 43 | # endif 44 | 45 | typedef m3ret_t (vectorcall * IM3Operation) (d_m3OpSig); 46 | 47 | #define d_m3RetSig static inline m3ret_t vectorcall 48 | #define d_m3Op(NAME) M3_NO_UBSAN d_m3RetSig op_##NAME (d_m3OpSig) 49 | 50 | #define nextOpImpl() ((IM3Operation)(* _pc))(_pc + 1, d_m3OpArgs) 51 | #define jumpOpImpl(PC) ((IM3Operation)(* PC))( PC + 1, d_m3OpArgs) 52 | 53 | #define nextOpDirect() M3_MUSTTAIL return nextOpImpl() 54 | #define jumpOpDirect(PC) M3_MUSTTAIL return jumpOpImpl((pc_t)(PC)) 55 | 56 | d_m3RetSig RunCode (d_m3OpSig) 57 | { 58 | nextOpDirect(); 59 | } 60 | 61 | d_m3EndExternC 62 | 63 | #endif // m3_exec_defs_h 64 | -------------------------------------------------------------------------------- /cpp/m3_function.c: -------------------------------------------------------------------------------- 1 | // 2 | // m3_function.c 3 | // 4 | // Created by Steven Massey on 4/7/21. 5 | // Copyright © 2021 Steven Massey. All rights reserved. 6 | // 7 | 8 | #include "m3_function.h" 9 | #include "m3_env.h" 10 | 11 | 12 | M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numTypes) 13 | { 14 | *o_functionType = (IM3FuncType) m3_Malloc ("M3FuncType", sizeof (M3FuncType) + i_numTypes); 15 | return (*o_functionType) ? m3Err_none : m3Err_mallocFailed; 16 | } 17 | 18 | 19 | bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB) 20 | { 21 | if (i_typeA->numRets == i_typeB->numRets && i_typeA->numArgs == i_typeB->numArgs) 22 | { 23 | return (memcmp (i_typeA->types, i_typeB->types, i_typeA->numRets + i_typeA->numArgs) == 0); 24 | } 25 | 26 | return false; 27 | } 28 | 29 | u16 GetFuncTypeNumParams (const IM3FuncType i_funcType) 30 | { 31 | return i_funcType ? i_funcType->numArgs : 0; 32 | } 33 | 34 | 35 | u8 GetFuncTypeParamType (const IM3FuncType i_funcType, u16 i_index) 36 | { 37 | u8 type = c_m3Type_unknown; 38 | 39 | if (i_funcType) 40 | { 41 | if (i_index < i_funcType->numArgs) 42 | { 43 | type = i_funcType->types [i_funcType->numRets + i_index]; 44 | } 45 | } 46 | 47 | return type; 48 | } 49 | 50 | 51 | 52 | u16 GetFuncTypeNumResults (const IM3FuncType i_funcType) 53 | { 54 | return i_funcType ? i_funcType->numRets : 0; 55 | } 56 | 57 | 58 | u8 GetFuncTypeResultType (const IM3FuncType i_funcType, u16 i_index) 59 | { 60 | u8 type = c_m3Type_unknown; 61 | 62 | if (i_funcType) 63 | { 64 | if (i_index < i_funcType->numRets) 65 | { 66 | type = i_funcType->types [i_index]; 67 | } 68 | } 69 | 70 | return type; 71 | } 72 | 73 | 74 | //--------------------------------------------------------------------------------------------------------------- 75 | 76 | 77 | void FreeImportInfo (M3ImportInfo * i_info) 78 | { 79 | m3_Free (i_info->moduleUtf8); 80 | m3_Free (i_info->fieldUtf8); 81 | } 82 | 83 | 84 | void Function_Release (IM3Function i_function) 85 | { 86 | m3_Free (i_function->constants); 87 | 88 | for (int i = 0; i < i_function->numNames; i++) 89 | { 90 | // name can be an alias of fieldUtf8 91 | if (i_function->names[i] != i_function->import.fieldUtf8) 92 | { 93 | m3_Free (i_function->names[i]); 94 | } 95 | } 96 | 97 | FreeImportInfo (& i_function->import); 98 | 99 | if (i_function->ownsWasmCode) 100 | m3_Free (i_function->wasm); 101 | 102 | // Function_FreeCompiledCode (func); 103 | 104 | # if (d_m3EnableCodePageRefCounting) 105 | { 106 | m3_Free (i_function->codePageRefs); 107 | i_function->numCodePageRefs = 0; 108 | } 109 | # endif 110 | } 111 | 112 | 113 | void Function_FreeCompiledCode (IM3Function i_function) 114 | { 115 | # if (d_m3EnableCodePageRefCounting) 116 | { 117 | i_function->compiled = NULL; 118 | 119 | while (i_function->numCodePageRefs--) 120 | { 121 | IM3CodePage page = i_function->codePageRefs [i_function->numCodePageRefs]; 122 | 123 | if (--(page->info.usageCount) == 0) 124 | { 125 | // printf ("free %p\n", page); 126 | } 127 | } 128 | 129 | m3_Free (i_function->codePageRefs); 130 | 131 | Runtime_ReleaseCodePages (i_function->module->runtime); 132 | } 133 | # endif 134 | } 135 | 136 | 137 | cstr_t m3_GetFunctionName (IM3Function i_function) 138 | { 139 | u16 numNames = 0; 140 | cstr_t *names = GetFunctionNames(i_function, &numNames); 141 | if (numNames > 0) 142 | return names[0]; 143 | else 144 | return ""; 145 | } 146 | 147 | 148 | IM3Module m3_GetFunctionModule (IM3Function i_function) 149 | { 150 | return i_function ? i_function->module : NULL; 151 | } 152 | 153 | 154 | cstr_t * GetFunctionNames (IM3Function i_function, u16 * o_numNames) 155 | { 156 | if (!i_function || !o_numNames) 157 | return NULL; 158 | 159 | if (i_function->import.fieldUtf8) 160 | { 161 | *o_numNames = 1; 162 | return &i_function->import.fieldUtf8; 163 | } 164 | else 165 | { 166 | *o_numNames = i_function->numNames; 167 | return i_function->names; 168 | } 169 | } 170 | 171 | 172 | cstr_t GetFunctionImportModuleName (IM3Function i_function) 173 | { 174 | return (i_function->import.moduleUtf8) ? i_function->import.moduleUtf8 : ""; 175 | } 176 | 177 | 178 | u16 GetFunctionNumArgs (IM3Function i_function) 179 | { 180 | u16 numArgs = 0; 181 | 182 | if (i_function) 183 | { 184 | if (i_function->funcType) 185 | numArgs = i_function->funcType->numArgs; 186 | } 187 | 188 | return numArgs; 189 | } 190 | 191 | u8 GetFunctionArgType (IM3Function i_function, u32 i_index) 192 | { 193 | u8 type = c_m3Type_none; 194 | 195 | if (i_index < GetFunctionNumArgs (i_function)) 196 | { 197 | u32 numReturns = i_function->funcType->numRets; 198 | 199 | type = i_function->funcType->types [numReturns + i_index]; 200 | } 201 | 202 | return type; 203 | } 204 | 205 | 206 | u16 GetFunctionNumReturns (IM3Function i_function) 207 | { 208 | u16 numReturns = 0; 209 | 210 | if (i_function) 211 | { 212 | if (i_function->funcType) 213 | numReturns = i_function->funcType->numRets; 214 | } 215 | 216 | return numReturns; 217 | } 218 | 219 | 220 | u8 GetFunctionReturnType (const IM3Function i_function, u16 i_index) 221 | { 222 | return i_function ? GetFuncTypeResultType (i_function->funcType, i_index) : c_m3Type_unknown; 223 | } 224 | 225 | 226 | u32 GetFunctionNumArgsAndLocals (IM3Function i_function) 227 | { 228 | if (i_function) 229 | return i_function->numLocals + GetFunctionNumArgs (i_function); 230 | else 231 | return 0; 232 | } 233 | 234 | -------------------------------------------------------------------------------- /cpp/m3_function.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_function.h 3 | // 4 | // Created by Steven Massey on 4/7/21. 5 | // Copyright © 2021 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_function_h 9 | #define m3_function_h 10 | 11 | #include "m3_core.h" 12 | 13 | d_m3BeginExternC 14 | 15 | //--------------------------------------------------------------------------------------------------------------------------------- 16 | 17 | typedef struct M3FuncType 18 | { 19 | struct M3FuncType * next; 20 | 21 | u16 numRets; 22 | u16 numArgs; 23 | u8 types []; // returns, then args 24 | } 25 | M3FuncType; 26 | 27 | typedef M3FuncType * IM3FuncType; 28 | 29 | 30 | M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numTypes); 31 | bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB); 32 | 33 | u16 GetFuncTypeNumParams (const IM3FuncType i_funcType); 34 | u8 GetFuncTypeParamType (const IM3FuncType i_funcType, u16 i_index); 35 | 36 | u16 GetFuncTypeNumResults (const IM3FuncType i_funcType); 37 | u8 GetFuncTypeResultType (const IM3FuncType i_funcType, u16 i_index); 38 | 39 | //--------------------------------------------------------------------------------------------------------------------------------- 40 | 41 | typedef struct M3Function 42 | { 43 | struct M3Module * module; 44 | 45 | M3ImportInfo import; 46 | 47 | bytes_t wasm; 48 | bytes_t wasmEnd; 49 | 50 | cstr_t names[d_m3MaxDuplicateFunctionImpl]; 51 | cstr_t export_name; // should be a part of "names" 52 | u16 numNames; // maximum of d_m3MaxDuplicateFunctionImpl 53 | 54 | IM3FuncType funcType; 55 | 56 | pc_t compiled; 57 | 58 | # if (d_m3EnableCodePageRefCounting) 59 | IM3CodePage * codePageRefs; // array of all pages used 60 | u32 numCodePageRefs; 61 | # endif 62 | 63 | # if defined (DEBUG) 64 | u32 hits; 65 | u32 index; 66 | # endif 67 | 68 | u16 maxStackSlots; 69 | 70 | u16 numRetSlots; 71 | u16 numRetAndArgSlots; 72 | 73 | u16 numLocals; // not including args 74 | u16 numLocalBytes; 75 | 76 | bool ownsWasmCode; 77 | 78 | u16 numConstantBytes; 79 | void * constants; 80 | } 81 | M3Function; 82 | 83 | void Function_Release (IM3Function i_function); 84 | void Function_FreeCompiledCode (IM3Function i_function); 85 | 86 | cstr_t GetFunctionImportModuleName (IM3Function i_function); 87 | cstr_t * GetFunctionNames (IM3Function i_function, u16 * o_numNames); 88 | u16 GetFunctionNumArgs (IM3Function i_function); 89 | u8 GetFunctionArgType (IM3Function i_function, u32 i_index); 90 | 91 | u16 GetFunctionNumReturns (IM3Function i_function); 92 | u8 GetFunctionReturnType (const IM3Function i_function, u16 i_index); 93 | 94 | u32 GetFunctionNumArgsAndLocals (IM3Function i_function); 95 | 96 | cstr_t SPrintFunctionArgList (IM3Function i_function, m3stack_t i_sp); 97 | 98 | //--------------------------------------------------------------------------------------------------------------------------------- 99 | 100 | 101 | d_m3EndExternC 102 | 103 | #endif /* m3_function_h */ 104 | -------------------------------------------------------------------------------- /cpp/m3_info.h: -------------------------------------------------------------------------------- 1 | // 2 | // m3_info.h 3 | // 4 | // Created by Steven Massey on 12/6/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #ifndef m3_info_h 9 | #define m3_info_h 10 | 11 | #include "m3_compile.h" 12 | 13 | d_m3BeginExternC 14 | 15 | void ProfileHit (cstr_t i_operationName); 16 | 17 | #ifdef DEBUG 18 | 19 | void dump_type_stack (IM3Compilation o); 20 | void log_opcode (IM3Compilation o, m3opcode_t i_opcode); 21 | const char * get_indention_string (IM3Compilation o); 22 | void log_emit (IM3Compilation o, IM3Operation i_operation); 23 | 24 | cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType); 25 | 26 | #else // DEBUG 27 | 28 | #define dump_type_stack(...) {} 29 | #define log_opcode(...) {} 30 | #define get_indention_string(...) "" 31 | #define emit_stack_dump(...) {} 32 | #define log_emit(...) {} 33 | 34 | #endif // DEBUG 35 | 36 | d_m3EndExternC 37 | 38 | #endif // m3_info_h 39 | -------------------------------------------------------------------------------- /cpp/m3_module.c: -------------------------------------------------------------------------------- 1 | // 2 | // m3_module.c 3 | // 4 | // Created by Steven Massey on 5/7/19. 5 | // Copyright © 2019 Steven Massey. All rights reserved. 6 | // 7 | 8 | #include "m3_env.h" 9 | #include "m3_exception.h" 10 | 11 | 12 | void Module_FreeFunctions (IM3Module i_module) 13 | { 14 | for (u32 i = 0; i < i_module->numFunctions; ++i) 15 | { 16 | IM3Function func = & i_module->functions [i]; 17 | Function_Release (func); 18 | } 19 | } 20 | 21 | 22 | void m3_FreeModule (IM3Module i_module) 23 | { 24 | if (i_module) 25 | { 26 | m3log (module, "freeing module: %s (funcs: %d; segments: %d)", 27 | i_module->name, i_module->numFunctions, i_module->numDataSegments); 28 | 29 | Module_FreeFunctions (i_module); 30 | 31 | m3_Free (i_module->functions); 32 | //m3_Free (i_module->imports); 33 | m3_Free (i_module->funcTypes); 34 | m3_Free (i_module->dataSegments); 35 | m3_Free (i_module->table0); 36 | 37 | for (u32 i = 0; i < i_module->numGlobals; ++i) 38 | { 39 | m3_Free (i_module->globals[i].name); 40 | FreeImportInfo(&(i_module->globals[i].import)); 41 | } 42 | m3_Free (i_module->globals); 43 | 44 | m3_Free (i_module); 45 | } 46 | } 47 | 48 | 49 | M3Result Module_AddGlobal (IM3Module io_module, IM3Global * o_global, u8 i_type, bool i_mutable, bool i_isImported) 50 | { 51 | _try { 52 | u32 index = io_module->numGlobals++; 53 | io_module->globals = m3_ReallocArray (M3Global, io_module->globals, io_module->numGlobals, index); 54 | _throwifnull (io_module->globals); 55 | M3Global * global = & io_module->globals [index]; 56 | 57 | global->type = i_type; 58 | global->imported = i_isImported; 59 | global->isMutable = i_mutable; 60 | 61 | if (o_global) 62 | * o_global = global; 63 | 64 | } _catch: 65 | return result; 66 | } 67 | 68 | M3Result Module_PreallocFunctions (IM3Module io_module, u32 i_totalFunctions) 69 | { 70 | _try { 71 | if (i_totalFunctions > io_module->allFunctions) { 72 | io_module->functions = m3_ReallocArray (M3Function, io_module->functions, i_totalFunctions, io_module->allFunctions); 73 | io_module->allFunctions = i_totalFunctions; 74 | _throwifnull (io_module->functions); 75 | } 76 | } _catch: 77 | return result; 78 | } 79 | 80 | M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo) 81 | { 82 | _try { 83 | 84 | u32 index = io_module->numFunctions++; 85 | _ (Module_PreallocFunctions(io_module, io_module->numFunctions)); 86 | 87 | _throwif ("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes); 88 | 89 | IM3FuncType ft = io_module->funcTypes [i_typeIndex]; 90 | 91 | IM3Function func = Module_GetFunction (io_module, index); 92 | func->funcType = ft; 93 | 94 | # ifdef DEBUG 95 | func->index = index; 96 | # endif 97 | 98 | if (i_importInfo and func->numNames == 0) 99 | { 100 | func->import = * i_importInfo; 101 | func->names[0] = i_importInfo->fieldUtf8; 102 | func->numNames = 1; 103 | } 104 | 105 | m3log (module, " added function: %3d; sig: %d", index, i_typeIndex); 106 | 107 | } _catch: 108 | return result; 109 | } 110 | 111 | #ifdef DEBUG 112 | void Module_GenerateNames (IM3Module i_module) 113 | { 114 | for (u32 i = 0; i < i_module->numFunctions; ++i) 115 | { 116 | IM3Function func = & i_module->functions [i]; 117 | 118 | if (func->numNames == 0) 119 | { 120 | char* buff = m3_AllocArray(char, 16); 121 | snprintf(buff, 16, "$func%d", i); 122 | func->names[0] = buff; 123 | func->numNames = 1; 124 | } 125 | } 126 | for (u32 i = 0; i < i_module->numGlobals; ++i) 127 | { 128 | IM3Global global = & i_module->globals [i]; 129 | 130 | if (global->name == NULL) 131 | { 132 | char* buff = m3_AllocArray(char, 16); 133 | snprintf(buff, 16, "$global%d", i); 134 | global->name = buff; 135 | } 136 | } 137 | } 138 | #endif 139 | 140 | IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex) 141 | { 142 | IM3Function func = NULL; 143 | 144 | if (i_functionIndex < i_module->numFunctions) 145 | { 146 | func = & i_module->functions [i_functionIndex]; 147 | //func->module = i_module; 148 | } 149 | 150 | return func; 151 | } 152 | 153 | 154 | const char* m3_GetModuleName (IM3Module i_module) 155 | { 156 | if (!i_module || !i_module->name) 157 | return ".unnamed"; 158 | 159 | return i_module->name; 160 | } 161 | 162 | void m3_SetModuleName (IM3Module i_module, const char* name) 163 | { 164 | if (i_module) i_module->name = name; 165 | } 166 | 167 | IM3Runtime m3_GetModuleRuntime (IM3Module i_module) 168 | { 169 | return i_module ? i_module->runtime : NULL; 170 | } 171 | 172 | -------------------------------------------------------------------------------- /cpp/react-native-webassembly.h: -------------------------------------------------------------------------------- 1 | #ifndef WEBASSEMBLY_H 2 | #define WEBASSEMBLY_H 3 | 4 | namespace facebook { 5 | namespace jsi { 6 | class Runtime; 7 | } 8 | } 9 | 10 | namespace webassembly { 11 | void install(facebook::jsi::Runtime &jsiRuntime); 12 | } 13 | 14 | #endif /* WEBASSEMBLY_H */ 15 | -------------------------------------------------------------------------------- /cpp/wasm3_defs.h: -------------------------------------------------------------------------------- 1 | // 2 | // wasm3_defs.h 3 | // 4 | // Created by Volodymyr Shymanskyy on 11/20/19. 5 | // Copyright © 2019 Volodymyr Shymanskyy. All rights reserved. 6 | // 7 | 8 | #ifndef wasm3_defs_h 9 | #define wasm3_defs_h 10 | 11 | #define M3_STR__(x) #x 12 | #define M3_STR(x) M3_STR__(x) 13 | 14 | #define M3_CONCAT__(a,b) a##b 15 | #define M3_CONCAT(a,b) M3_CONCAT__(a,b) 16 | 17 | /* 18 | * Detect compiler 19 | */ 20 | 21 | # if defined(__clang__) 22 | # define M3_COMPILER_CLANG 1 23 | # elif defined(__INTEL_COMPILER) 24 | # define M3_COMPILER_ICC 1 25 | # elif defined(__GNUC__) || defined(__GNUG__) 26 | # define M3_COMPILER_GCC 1 27 | # elif defined(_MSC_VER) 28 | # define M3_COMPILER_MSVC 1 29 | # else 30 | # warning "Compiler not detected" 31 | # endif 32 | 33 | # if defined(M3_COMPILER_CLANG) 34 | # if defined(WIN32) 35 | # define M3_COMPILER_VER __VERSION__ " for Windows" 36 | # else 37 | # define M3_COMPILER_VER __VERSION__ 38 | # endif 39 | # elif defined(M3_COMPILER_GCC) 40 | # define M3_COMPILER_VER "GCC " __VERSION__ 41 | # elif defined(M3_COMPILER_ICC) 42 | # define M3_COMPILER_VER __VERSION__ 43 | # elif defined(M3_COMPILER_MSVC) 44 | # define M3_COMPILER_VER "MSVC " M3_STR(_MSC_VER) 45 | # else 46 | # define M3_COMPILER_VER "unknown" 47 | # endif 48 | 49 | # ifdef __has_feature 50 | # define M3_COMPILER_HAS_FEATURE(x) __has_feature(x) 51 | # else 52 | # define M3_COMPILER_HAS_FEATURE(x) 0 53 | # endif 54 | 55 | # ifdef __has_builtin 56 | # define M3_COMPILER_HAS_BUILTIN(x) __has_builtin(x) 57 | # else 58 | # define M3_COMPILER_HAS_BUILTIN(x) 0 59 | # endif 60 | 61 | # ifdef __has_attribute 62 | # define M3_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x) 63 | # else 64 | # define M3_COMPILER_HAS_ATTRIBUTE(x) 0 65 | # endif 66 | 67 | /* 68 | * Detect endianness 69 | */ 70 | 71 | # if defined(M3_COMPILER_MSVC) 72 | # define M3_LITTLE_ENDIAN 73 | # elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 74 | # define M3_LITTLE_ENDIAN 75 | # elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 76 | # define M3_BIG_ENDIAN 77 | # else 78 | # error "Byte order not detected" 79 | # endif 80 | 81 | /* 82 | * Detect platform 83 | */ 84 | 85 | # if defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_GCC) || defined(M3_COMPILER_ICC) 86 | # if defined(__wasm__) 87 | # define M3_ARCH "wasm" 88 | 89 | # elif defined(__x86_64__) 90 | # define M3_ARCH "x86_64" 91 | 92 | # elif defined(__i386__) 93 | # define M3_ARCH "i386" 94 | 95 | # elif defined(__aarch64__) 96 | # define M3_ARCH "arm64-v8a" 97 | 98 | # elif defined(__arm__) 99 | # if defined(__ARM_ARCH_7A__) 100 | # if defined(__ARM_NEON__) 101 | # if defined(__ARM_PCS_VFP) 102 | # define M3_ARCH "arm-v7a/NEON hard-float" 103 | # else 104 | # define M3_ARCH "arm-v7a/NEON" 105 | # endif 106 | # else 107 | # if defined(__ARM_PCS_VFP) 108 | # define M3_ARCH "arm-v7a hard-float" 109 | # else 110 | # define M3_ARCH "arm-v7a" 111 | # endif 112 | # endif 113 | # else 114 | # define M3_ARCH "arm" 115 | # endif 116 | 117 | # elif defined(__riscv) 118 | # if defined(__riscv_32e) 119 | # define _M3_ARCH_RV "rv32e" 120 | # elif __riscv_xlen == 128 121 | # define _M3_ARCH_RV "rv128i" 122 | # elif __riscv_xlen == 64 123 | # define _M3_ARCH_RV "rv64i" 124 | # elif __riscv_xlen == 32 125 | # define _M3_ARCH_RV "rv32i" 126 | # endif 127 | # if defined(__riscv_muldiv) 128 | # define _M3_ARCH_RV_M _M3_ARCH_RV "m" 129 | # else 130 | # define _M3_ARCH_RV_M _M3_ARCH_RV 131 | # endif 132 | # if defined(__riscv_atomic) 133 | # define _M3_ARCH_RV_A _M3_ARCH_RV_M "a" 134 | # else 135 | # define _M3_ARCH_RV_A _M3_ARCH_RV_M 136 | # endif 137 | # if defined(__riscv_flen) 138 | # define _M3_ARCH_RV_F _M3_ARCH_RV_A "f" 139 | # else 140 | # define _M3_ARCH_RV_F _M3_ARCH_RV_A 141 | # endif 142 | # if defined(__riscv_flen) && __riscv_flen >= 64 143 | # define _M3_ARCH_RV_D _M3_ARCH_RV_F "d" 144 | # else 145 | # define _M3_ARCH_RV_D _M3_ARCH_RV_F 146 | # endif 147 | # if defined(__riscv_compressed) 148 | # define _M3_ARCH_RV_C _M3_ARCH_RV_D "c" 149 | # else 150 | # define _M3_ARCH_RV_C _M3_ARCH_RV_D 151 | # endif 152 | # define M3_ARCH _M3_ARCH_RV_C 153 | 154 | # elif defined(__mips__) 155 | # if defined(__MIPSEB__) && defined(__mips64) 156 | # define M3_ARCH "mips64 " _MIPS_ARCH 157 | # elif defined(__MIPSEL__) && defined(__mips64) 158 | # define M3_ARCH "mips64el " _MIPS_ARCH 159 | # elif defined(__MIPSEB__) 160 | # define M3_ARCH "mips " _MIPS_ARCH 161 | # elif defined(__MIPSEL__) 162 | # define M3_ARCH "mipsel " _MIPS_ARCH 163 | # endif 164 | 165 | # elif defined(__PPC__) 166 | # if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) 167 | # define M3_ARCH "ppc64le" 168 | # elif defined(__PPC64__) 169 | # define M3_ARCH "ppc64" 170 | # else 171 | # define M3_ARCH "ppc" 172 | # endif 173 | 174 | # elif defined(__sparc__) 175 | # if defined(__arch64__) 176 | # define M3_ARCH "sparc64" 177 | # else 178 | # define M3_ARCH "sparc" 179 | # endif 180 | 181 | # elif defined(__s390x__) 182 | # define M3_ARCH "s390x" 183 | 184 | # elif defined(__alpha__) 185 | # define M3_ARCH "alpha" 186 | 187 | # elif defined(__m68k__) 188 | # define M3_ARCH "m68k" 189 | 190 | # elif defined(__xtensa__) 191 | # define M3_ARCH "xtensa" 192 | 193 | # elif defined(__arc__) 194 | # define M3_ARCH "arc32" 195 | 196 | # elif defined(__AVR__) 197 | # define M3_ARCH "avr" 198 | # endif 199 | # endif 200 | 201 | # if defined(M3_COMPILER_MSVC) 202 | # if defined(_M_X64) 203 | # define M3_ARCH "x86_64" 204 | # elif defined(_M_IX86) 205 | # define M3_ARCH "i386" 206 | # elif defined(_M_ARM64) 207 | # define M3_ARCH "arm64" 208 | # elif defined(_M_ARM) 209 | # define M3_ARCH "arm" 210 | # endif 211 | # endif 212 | 213 | # if !defined(M3_ARCH) 214 | # warning "Architecture not detected" 215 | # define M3_ARCH "unknown" 216 | # endif 217 | 218 | /* 219 | * Byte swapping (for Big-Endian systems only) 220 | */ 221 | 222 | # if defined(M3_COMPILER_MSVC) 223 | # define m3_bswap16(x) _byteswap_ushort((x)) 224 | # define m3_bswap32(x) _byteswap_ulong((x)) 225 | # define m3_bswap64(x) _byteswap_uint64((x)) 226 | # elif defined(M3_COMPILER_GCC) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) 227 | // __builtin_bswap32/64 added in gcc 4.3, __builtin_bswap16 added in gcc 4.8 228 | # define m3_bswap16(x) __builtin_bswap16((x)) 229 | # define m3_bswap32(x) __builtin_bswap32((x)) 230 | # define m3_bswap64(x) __builtin_bswap64((x)) 231 | # elif defined(M3_COMPILER_CLANG) && M3_COMPILER_HAS_BUILTIN(__builtin_bswap16) 232 | # define m3_bswap16(x) __builtin_bswap16((x)) 233 | # define m3_bswap32(x) __builtin_bswap32((x)) 234 | # define m3_bswap64(x) __builtin_bswap64((x)) 235 | # elif defined(M3_COMPILER_ICC) 236 | # define m3_bswap16(x) __builtin_bswap16((x)) 237 | # define m3_bswap32(x) __builtin_bswap32((x)) 238 | # define m3_bswap64(x) __builtin_bswap64((x)) 239 | # else 240 | # ifdef __linux__ 241 | # include 242 | # else 243 | # include 244 | # endif 245 | # if defined(__bswap_16) 246 | # define m3_bswap16(x) __bswap_16((x)) 247 | # define m3_bswap32(x) __bswap_32((x)) 248 | # define m3_bswap64(x) __bswap_64((x)) 249 | # else 250 | # warning "Using naive (probably slow) bswap operations" 251 | static inline 252 | uint16_t m3_bswap16(uint16_t x) { 253 | return ((( x >> 8 ) & 0xffu ) | (( x & 0xffu ) << 8 )); 254 | } 255 | static inline 256 | uint32_t m3_bswap32(uint32_t x) { 257 | return ((( x & 0xff000000u ) >> 24 ) | 258 | (( x & 0x00ff0000u ) >> 8 ) | 259 | (( x & 0x0000ff00u ) << 8 ) | 260 | (( x & 0x000000ffu ) << 24 )); 261 | } 262 | static inline 263 | uint64_t m3_bswap64(uint64_t x) { 264 | return ((( x & 0xff00000000000000ull ) >> 56 ) | 265 | (( x & 0x00ff000000000000ull ) >> 40 ) | 266 | (( x & 0x0000ff0000000000ull ) >> 24 ) | 267 | (( x & 0x000000ff00000000ull ) >> 8 ) | 268 | (( x & 0x00000000ff000000ull ) << 8 ) | 269 | (( x & 0x0000000000ff0000ull ) << 24 ) | 270 | (( x & 0x000000000000ff00ull ) << 40 ) | 271 | (( x & 0x00000000000000ffull ) << 56 )); 272 | } 273 | # endif 274 | # endif 275 | 276 | /* 277 | * Bit ops 278 | */ 279 | #define m3_isBitSet(val, pos) ((val & (1 << pos)) != 0) 280 | 281 | /* 282 | * Other 283 | */ 284 | 285 | # if defined(M3_COMPILER_GCC) || defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_ICC) 286 | # define M3_UNLIKELY(x) __builtin_expect(!!(x), 0) 287 | # define M3_LIKELY(x) __builtin_expect(!!(x), 1) 288 | # else 289 | # define M3_UNLIKELY(x) (x) 290 | # define M3_LIKELY(x) (x) 291 | # endif 292 | 293 | #endif // wasm3_defs_h 294 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.node-version: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /example/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.6 2 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby File.read(File.join(__dir__, '.ruby-version')).strip 5 | 6 | gem 'cocoapods', '~> 1.11', '>= 1.11.3' 7 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | ### How to compile a `.wat` file: 2 | 3 | 1. Download and configure [__WebAssembly Binary Toolkit__](https://github.com/WebAssembly/wabt). 4 | 2. Then you can use something like: `wat2wasm test.wat -o test.wasm`. 5 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "com.facebook.react" 3 | 4 | import com.android.build.OutputFile 5 | 6 | /** 7 | * This is the configuration block to customize your React Native Android app. 8 | * By default you don't need to apply any configuration, just uncomment the lines you need. 9 | */ 10 | react { 11 | /* Folders */ 12 | // The root of your project, i.e. where "package.json" lives. Default is '..' 13 | // root = file("../") 14 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native 15 | // reactNativeDir = file("../node_modules/react-native") 16 | // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen 17 | // codegenDir = file("../node_modules/react-native-codegen") 18 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js 19 | // cliFile = file("../node_modules/react-native/cli.js") 20 | 21 | /* Variants */ 22 | // The list of variants to that are debuggable. For those we're going to 23 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 24 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 25 | // debuggableVariants = ["liteDebug", "prodDebug"] 26 | 27 | /* Bundling */ 28 | // A list containing the node command and its flags. Default is just 'node'. 29 | // nodeExecutableAndArgs = ["node"] 30 | // 31 | // The command to run when bundling. By default is 'bundle' 32 | // bundleCommand = "ram-bundle" 33 | // 34 | // The path to the CLI configuration file. Default is empty. 35 | // bundleConfig = file(../rn-cli.config.js) 36 | // 37 | // The name of the generated asset file containing your JS bundle 38 | // bundleAssetName = "MyApplication.android.bundle" 39 | // 40 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 41 | // entryFile = file("../js/MyApplication.android.js") 42 | // 43 | // A list of extra flags to pass to the 'bundle' commands. 44 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 45 | // extraPackagerArgs = [] 46 | 47 | /* Hermes Commands */ 48 | // The hermes compiler command to run. By default it is 'hermesc' 49 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 50 | // 51 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 52 | // hermesFlags = ["-O", "-output-source-map"] 53 | } 54 | 55 | /** 56 | * Set this to true to create four separate APKs instead of one, 57 | * one for each native architecture. This is useful if you don't 58 | * use App Bundles (https://developer.android.com/guide/app-bundle/) 59 | * and want to have separate APKs to upload to the Play Store. 60 | */ 61 | def enableSeparateBuildPerCPUArchitecture = false 62 | 63 | /** 64 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 65 | */ 66 | def enableProguardInReleaseBuilds = false 67 | 68 | /** 69 | * The preferred build flavor of JavaScriptCore (JSC) 70 | * 71 | * For example, to use the international variant, you can use: 72 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 73 | * 74 | * The international variant includes ICU i18n library and necessary data 75 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 76 | * give correct results when using with locales other than en-US. Note that 77 | * this variant is about 6MiB larger per architecture than default. 78 | */ 79 | def jscFlavor = 'org.webkit:android-jsc:+' 80 | 81 | /** 82 | * Private function to get the list of Native Architectures you want to build. 83 | * This reads the value from reactNativeArchitectures in your gradle.properties 84 | * file and works together with the --active-arch-only flag of react-native run-android. 85 | */ 86 | def reactNativeArchitectures() { 87 | def value = project.getProperties().get("reactNativeArchitectures") 88 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 89 | } 90 | 91 | android { 92 | ndkVersion rootProject.ext.ndkVersion 93 | 94 | compileSdkVersion rootProject.ext.compileSdkVersion 95 | 96 | namespace "com.webassemblyexample" 97 | defaultConfig { 98 | applicationId "com.webassemblyexample" 99 | minSdkVersion rootProject.ext.minSdkVersion 100 | targetSdkVersion rootProject.ext.targetSdkVersion 101 | versionCode 1 102 | versionName "1.0" 103 | } 104 | 105 | splits { 106 | abi { 107 | reset() 108 | enable enableSeparateBuildPerCPUArchitecture 109 | universalApk false // If true, also generate a universal APK 110 | include (*reactNativeArchitectures()) 111 | } 112 | } 113 | signingConfigs { 114 | debug { 115 | storeFile file('debug.keystore') 116 | storePassword 'android' 117 | keyAlias 'androiddebugkey' 118 | keyPassword 'android' 119 | } 120 | } 121 | buildTypes { 122 | debug { 123 | signingConfig signingConfigs.debug 124 | } 125 | release { 126 | // Caution! In production, you need to generate your own keystore file. 127 | // see https://reactnative.dev/docs/signed-apk-android. 128 | signingConfig signingConfigs.debug 129 | minifyEnabled enableProguardInReleaseBuilds 130 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 131 | } 132 | } 133 | 134 | // applicationVariants are e.g. debug, release 135 | applicationVariants.all { variant -> 136 | variant.outputs.each { output -> 137 | // For each separate APK per architecture, set a unique version code as described here: 138 | // https://developer.android.com/studio/build/configure-apk-splits.html 139 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. 140 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 141 | def abi = output.getFilter(OutputFile.ABI) 142 | if (abi != null) { // null for the universal-debug, universal-release variants 143 | output.versionCodeOverride = 144 | defaultConfig.versionCode * 1000 + versionCodes.get(abi) 145 | } 146 | 147 | } 148 | } 149 | } 150 | 151 | dependencies { 152 | // The version of react-native is set by the React Native Gradle Plugin 153 | implementation("com.facebook.react:react-android") 154 | 155 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") 156 | 157 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") 158 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { 159 | exclude group:'com.squareup.okhttp3', module:'okhttp' 160 | } 161 | 162 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") 163 | if (hermesEnabled.toBoolean()) { 164 | implementation("com.facebook.react:hermes-android") 165 | } else { 166 | implementation jscFlavor 167 | } 168 | } 169 | 170 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 171 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/debug.keystore -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/android/app/src/debug/java/com/webassemblyexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.webassemblyexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 21 | import com.facebook.react.ReactInstanceEventListener; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | /** 28 | * Class responsible of loading Flipper inside your React Native application. This is the debug 29 | * flavor of it. Here you can add your own plugins and customize the Flipper setup. 30 | */ 31 | public class ReactNativeFlipper { 32 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 33 | if (FlipperUtils.shouldEnableFlipper(context)) { 34 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 35 | 36 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 37 | client.addPlugin(new DatabasesFlipperPlugin(context)); 38 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 39 | client.addPlugin(CrashReporterPlugin.getInstance()); 40 | 41 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 42 | NetworkingModule.setCustomClientBuilder( 43 | new NetworkingModule.CustomClientBuilder() { 44 | @Override 45 | public void apply(OkHttpClient.Builder builder) { 46 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 47 | } 48 | }); 49 | client.addPlugin(networkFlipperPlugin); 50 | client.start(); 51 | 52 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 53 | // Hence we run if after all native modules have been initialized 54 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 55 | if (reactContext == null) { 56 | reactInstanceManager.addReactInstanceEventListener( 57 | new ReactInstanceEventListener() { 58 | @Override 59 | public void onReactContextInitialized(ReactContext reactContext) { 60 | reactInstanceManager.removeReactInstanceEventListener(this); 61 | reactContext.runOnNativeModulesQueueThread( 62 | new Runnable() { 63 | @Override 64 | public void run() { 65 | client.addPlugin(new FrescoFlipperPlugin()); 66 | } 67 | }); 68 | } 69 | }); 70 | } else { 71 | client.addPlugin(new FrescoFlipperPlugin()); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/webassemblyexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.webassemblyexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate; 7 | 8 | public class MainActivity extends ReactActivity { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | @Override 15 | protected String getMainComponentName() { 16 | return "WebassemblyExample"; 17 | } 18 | 19 | /** 20 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link 21 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React 22 | * (aka React 18) with two boolean flags. 23 | */ 24 | @Override 25 | protected ReactActivityDelegate createReactActivityDelegate() { 26 | return new DefaultReactActivityDelegate( 27 | this, 28 | getMainComponentName(), 29 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 30 | DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled 31 | // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). 32 | DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/webassemblyexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.webassemblyexample; 2 | 3 | import android.app.Application; 4 | import com.facebook.react.PackageList; 5 | import com.facebook.react.ReactApplication; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 9 | import com.facebook.react.defaults.DefaultReactNativeHost; 10 | import com.facebook.soloader.SoLoader; 11 | import java.util.List; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new DefaultReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | @SuppressWarnings("UnnecessaryLocalVariable") 25 | List packages = new PackageList(this).getPackages(); 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(new MyReactNativePackage()); 28 | return packages; 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | 36 | @Override 37 | protected boolean isNewArchEnabled() { 38 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 39 | } 40 | 41 | @Override 42 | protected Boolean isHermesEnabled() { 43 | return BuildConfig.IS_HERMES_ENABLED; 44 | } 45 | }; 46 | 47 | @Override 48 | public ReactNativeHost getReactNativeHost() { 49 | return mReactNativeHost; 50 | } 51 | 52 | @Override 53 | public void onCreate() { 54 | super.onCreate(); 55 | SoLoader.init(this, /* native exopackage */ false); 56 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 57 | // If you opted-in for the New Architecture, we load the native entry point for this app. 58 | DefaultNewArchitectureEntryPoint.load(); 59 | } 60 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WebassemblyExample 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/release/java/com/webassemblyexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.webassemblyexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.react.ReactInstanceManager; 11 | 12 | /** 13 | * Class responsible of loading Flipper inside your React Native application. This is the release 14 | * flavor of it so it's empty as we don't want to load Flipper. 15 | */ 16 | public class ReactNativeFlipper { 17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 18 | // Do nothing as we don't want to initialize Flipper on Release. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "33.0.0" 6 | minSdkVersion = 21 7 | compileSdkVersion = 33 8 | targetSdkVersion = 33 9 | 10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. 11 | ndkVersion = "23.1.7779620" 12 | } 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | dependencies { 18 | classpath("com.android.tools.build:gradle:7.3.1") 19 | classpath("com.facebook.react:react-native-gradle-plugin") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.125.0 29 | 30 | # Use this property to specify which architecture you want to build. 31 | # You can also override it from the CLI using 32 | # ./gradlew -PreactNativeArchitectures=x86_64 33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 34 | 35 | # Use this property to enable support to the new architecture. 36 | # This will allow you to use TurboModules and the Fabric render in 37 | # your application. You should enable this flag either if you want 38 | # to write custom TurboModules/Fabric components OR use libraries that 39 | # are providing them. 40 | newArchEnabled=true 41 | 42 | # Use this property to enable or disable the Hermes JS engine. 43 | # If set to false, you will be using JSC instead. 44 | hermesEnabled=true 45 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cawfree/react-native-webassembly/2da2f177d044556a954ade6acb909bbf437bdeb5/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'WebassemblyExample' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/react-native-gradle-plugin') 5 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WebassemblyExample", 3 | "displayName": "WebassemblyExample" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:metro-react-native-babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /example/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm' { 2 | const value: any; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // WebassemblyExample 4 | // 5 | 6 | import Foundation 7 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | ENV['RCT_NEW_ARCH_ENABLED'] = '1' 2 | 3 | require_relative '../node_modules/react-native/scripts/react_native_pods' 4 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 5 | 6 | platform :ios, min_ios_version_supported 7 | prepare_react_native_project! 8 | 9 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. 10 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded 11 | # 12 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` 13 | # ```js 14 | # module.exports = { 15 | # dependencies: { 16 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), 17 | # ``` 18 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled 19 | 20 | linkage = ENV['USE_FRAMEWORKS'] 21 | if linkage != nil 22 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 23 | use_frameworks! :linkage => linkage.to_sym 24 | end 25 | 26 | target 'WebassemblyExample' do 27 | config = use_native_modules! 28 | 29 | # Flags change depending on the env values. 30 | flags = get_default_flags() 31 | 32 | use_react_native!( 33 | :path => config[:reactNativePath], 34 | # Hermes is now enabled by default. Disable by setting this flag to false. 35 | # Upcoming versions of React Native may rely on get_default_flags(), but 36 | # we make it explicit here to aid in the React Native upgrade process. 37 | :hermes_enabled => flags[:hermes_enabled], 38 | :fabric_enabled => flags[:fabric_enabled], 39 | # Enables Flipper. 40 | # 41 | # Note that if you have use_frameworks! enabled, Flipper will not work and 42 | # you should disable the next line. 43 | :flipper_configuration => flipper_config, 44 | # An absolute path to your application root. 45 | :app_path => "#{Pod::Config.instance.installation_root}/.." 46 | ) 47 | 48 | target 'WebassemblyExampleTests' do 49 | inherit! :complete 50 | # Pods for testing 51 | end 52 | 53 | post_install do |installer| 54 | react_native_post_install( 55 | installer, 56 | # Set `mac_catalyst_enabled` to `true` in order to apply patches 57 | # necessary for Mac Catalyst builds 58 | :mac_catalyst_enabled => false 59 | ) 60 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample.xcodeproj/xcshareddata/xcschemes/WebassemblyExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"WebassemblyExample"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | #if DEBUG 20 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 21 | #else 22 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 23 | #endif 24 | } 25 | 26 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. 27 | /// 28 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html 29 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). 30 | /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. 31 | - (BOOL)concurrentRootEnabled 32 | { 33 | return true; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | WebassemblyExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/WebassemblyExampleTests/WebassemblyExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface WebassemblyExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation WebassemblyExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escape = require('escape-string-regexp'); 3 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 4 | const metroDefault = require('metro-config/src/defaults/defaults'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | 9 | const modules = Object.keys({ 10 | ...pak.peerDependencies, 11 | }); 12 | 13 | module.exports = { 14 | projectRoot: __dirname, 15 | watchFolders: [root], 16 | 17 | // We need to make sure that only one version is loaded for peerDependencies 18 | // So we block them at the root, and alias them to the versions in example's node_modules 19 | resolver: { 20 | blacklistRE: exclusionList( 21 | modules.map( 22 | (m) => 23 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 24 | ) 25 | ), 26 | 27 | extraNodeModules: modules.reduce((acc, name) => { 28 | acc[name] = path.join(__dirname, 'node_modules', name); 29 | return acc; 30 | }, {}), 31 | 32 | assetExts: metroDefault.assetExts.concat(['wasm']), 33 | }, 34 | 35 | transformer: { 36 | getTransformOptions: async () => ({ 37 | transform: { 38 | experimentalImportSupport: false, 39 | inlineRequires: true, 40 | }, 41 | }), 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WebassemblyExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "pods": "pod-install --quiet" 10 | }, 11 | "dependencies": { 12 | "axios": "1.3.4", 13 | "react": "18.2.0", 14 | "react-native": "0.71.4" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.20.0", 18 | "@babel/preset-env": "^7.20.0", 19 | "@babel/runtime": "^7.20.0", 20 | "babel-plugin-module-resolver": "^4.1.0", 21 | "metro-react-native-babel-preset": "0.73.8" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button, StyleSheet, View } from 'react-native'; 3 | 4 | import * as WebAssembly from 'react-native-webassembly'; 5 | 6 | import LocalHello from './sources/Local.Hello.wasm'; 7 | import LocalCallback from './sources/Local.Callback.wasm'; 8 | import LocalSimpleMemory from './sources/Local.SimpleMemory.wasm'; 9 | 10 | import { useWasmCircomRuntime, useWasmHelloWorld } from './hooks'; 11 | import { fetchWasm } from './utils'; 12 | 13 | export default function App() { 14 | const helloWorld = useWasmHelloWorld(); 15 | const helloWorldResult = 16 | 'result' in helloWorld ? helloWorld.result : undefined; 17 | const helloWorldError = 'error' in helloWorld ? helloWorld.error : undefined; 18 | 19 | const { calculateWTNSBin, error: circomError } = useWasmCircomRuntime(); 20 | 21 | /* Hook I/O. */ 22 | React.useEffect( 23 | () => void (helloWorldError && console.error(helloWorldError)), 24 | [helloWorldError] 25 | ); 26 | 27 | /* ZK Snark */ 28 | React.useEffect( 29 | () => void (circomError && console.error(circomError)), 30 | [circomError] 31 | ); 32 | 33 | /* Add. */ 34 | React.useEffect(() => { 35 | if (!helloWorldResult) return; 36 | 37 | const result = helloWorldResult.instance.exports.add(103, 202); 38 | 39 | if (result !== 305) throw new Error('Failed to add.'); 40 | }, [helloWorldResult]); 41 | 42 | /* Local imports. */ 43 | React.useEffect( 44 | () => 45 | void (async () => { 46 | try { 47 | const localModule = await WebAssembly.instantiate<{ 48 | readonly add: (a: number, b: number) => number; 49 | }>(LocalHello); 50 | 51 | const result = localModule.instance.exports.add(1000, 2000); 52 | 53 | if (result !== 3000) throw new Error('Failed to add. (Local)'); 54 | } catch (e) { 55 | console.error(e); 56 | } 57 | })(), 58 | [] 59 | ); 60 | 61 | /* complex allocation */ 62 | React.useEffect( 63 | () => 64 | void (async () => { 65 | try { 66 | /* complex */ 67 | await WebAssembly.instantiate( 68 | await fetchWasm( 69 | 'https://github.com/tact-lang/ton-wasm/raw/main/output/wasm/emulator-emscripten.wasm' 70 | ), 71 | {} 72 | ); 73 | } catch (e) { 74 | console.error(e); 75 | } 76 | })(), 77 | [] 78 | ); 79 | 80 | /* callback e2e */ 81 | React.useEffect( 82 | () => 83 | void (async () => { 84 | try { 85 | const localCallback = await WebAssembly.instantiate<{ 86 | readonly callBackFunction: (a: number) => number; 87 | }>(LocalCallback, { 88 | runtime: { 89 | callback: (a: number): number => a * 2, 90 | }, 91 | }); 92 | 93 | const result = localCallback.instance.exports.callBackFunction(25); 94 | 95 | if (result !== 50) throw new Error('Callback failure.'); 96 | } catch (e) { 97 | console.error(e); 98 | } 99 | })(), 100 | [] 101 | ); 102 | 103 | /* Simple memory. */ 104 | React.useEffect( 105 | () => 106 | void (async () => { 107 | try { 108 | const localSimpleMemory = await WebAssembly.instantiate<{ 109 | readonly write_byte_to_memory: (value: number) => void; 110 | readonly read_byte_from_memory: () => number; 111 | }>(LocalSimpleMemory); 112 | 113 | const testMemory = (withValue: number) => { 114 | localSimpleMemory.instance.exports.write_byte_to_memory(withValue); 115 | 116 | const wasmResult = 117 | localSimpleMemory.instance.exports.read_byte_from_memory(); 118 | 119 | if (wasmResult !== withValue) 120 | throw new Error( 121 | `Expected ${withValue}, encountered wasm ${wasmResult}.` 122 | ); 123 | 124 | const ab: ArrayBuffer = localSimpleMemory.instance.exports.memory!; 125 | 126 | const jsResult = new Uint8Array(ab.slice(0, 1))[0]; 127 | 128 | // Ensure the JavaScript buffer is up-to-date. 129 | if (jsResult !== withValue) 130 | throw new Error( 131 | `Expected ${withValue}, encountered js ${jsResult}.` 132 | ); 133 | }; 134 | 135 | for (let i = 0; i < 255; i += 1) testMemory(i); 136 | } catch (e) { 137 | console.error(e); 138 | } 139 | })(), 140 | [] 141 | ); 142 | 143 | return ( 144 | 145 |