(jsi);
16 |
17 | if (runtime) {
18 | webassembly::install(*runtime);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/src/sources/Local.SimpleMemory.wat:
--------------------------------------------------------------------------------
1 | (module
2 | ;; Define a memory block with one page (64KB) of memory
3 | (memory $my_memory 1)
4 |
5 | ;; Export the memory block so that it can be accessed from JavaScript
6 | (export "memory" (memory $my_memory))
7 |
8 | ;; Define a function that writes a byte to the first byte of memory
9 | (func (export "write_byte_to_memory") (param $value i32)
10 | (i32.store8 (i32.const 0) (local.get $value))
11 | )
12 |
13 | ;; Define a function that reads a byte from the first byte of memory
14 | (func (export "read_byte_from_memory") (result i32)
15 | (i32.load8_u (i32.const 0))
16 | )
17 | )
18 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "react-native-webassembly": ["./src/index"]
6 | },
7 | "allowUnreachableCode": false,
8 | "allowUnusedLabels": false,
9 | "esModuleInterop": true,
10 | "importsNotUsedAsValues": "error",
11 | "forceConsistentCasingInFileNames": true,
12 | "jsx": "react",
13 | "lib": ["esnext"],
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitReturns": true,
18 | "noImplicitUseStrict": false,
19 | "noStrictGenericChecks": false,
20 | "noUncheckedIndexedAccess": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": false,
23 | "resolveJsonModule": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "target": "esnext"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/cpp/m3_api_wasi.h:
--------------------------------------------------------------------------------
1 | //
2 | // m3_api_wasi.h
3 | //
4 | // Created by Volodymyr Shymanskyy on 11/20/19.
5 | // Copyright © 2019 Volodymyr Shymanskyy. All rights reserved.
6 | //
7 |
8 | #ifndef m3_api_wasi_h
9 | #define m3_api_wasi_h
10 |
11 | #include "m3_core.h"
12 |
13 | #if defined(d_m3HasUVWASI)
14 | #include "uvwasi.h"
15 | #endif
16 |
17 | d_m3BeginExternC
18 |
19 | typedef struct m3_wasi_context_t
20 | {
21 | i32 exit_code;
22 | u32 argc;
23 | ccstr_t * argv;
24 | } m3_wasi_context_t;
25 |
26 | M3Result m3_LinkWASI (IM3Module io_module);
27 |
28 | #if defined(d_m3HasUVWASI)
29 |
30 | M3Result m3_LinkWASIWithOptions (IM3Module io_module, uvwasi_options_t uvwasiOptions);
31 |
32 | #endif
33 |
34 | m3_wasi_context_t* m3_GetWasiContext();
35 |
36 | d_m3EndExternC
37 |
38 | #endif // m3_api_wasi_h
39 |
--------------------------------------------------------------------------------
/scripts/bootstrap.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 | const path = require('path');
3 | const child_process = require('child_process');
4 |
5 | const root = path.resolve(__dirname, '..');
6 | const args = process.argv.slice(2);
7 | const options = {
8 | cwd: process.cwd(),
9 | env: process.env,
10 | stdio: 'inherit',
11 | encoding: 'utf-8',
12 | };
13 |
14 | if (os.type() === 'Windows_NT') {
15 | options.shell = true;
16 | }
17 |
18 | let result;
19 |
20 | if (process.cwd() !== root || args.length) {
21 | // We're not in the root of the project, or additional arguments were passed
22 | // In this case, forward the command to `yarn`
23 | result = child_process.spawnSync('yarn', args, options);
24 | } else {
25 | // If `yarn` is run without arguments, perform bootstrap
26 | result = child_process.spawnSync('yarn', ['bootstrap'], options);
27 | }
28 |
29 | process.exitCode = result.status;
30 |
--------------------------------------------------------------------------------
/ios/Webassembly.mm:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 | #import
5 |
6 | #import "Webassembly.h"
7 | #import "react-native-webassembly.h"
8 |
9 | using namespace facebook::jsi;
10 | using namespace std;
11 |
12 | @implementation Webassembly
13 |
14 | @synthesize bridge = _bridge;
15 | @synthesize methodQueue = _methodQueue;
16 |
17 | RCT_EXPORT_MODULE()
18 |
19 | + (BOOL)requiresMainQueueSetup {
20 | return YES;
21 | }
22 |
23 | RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
24 | {
25 | RCTBridge* bridge = [RCTBridge currentBridge];
26 | RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
27 |
28 | if (cxxBridge == nil) return @false;
29 |
30 | auto jsiRuntime = (facebook::jsi::Runtime*) cxxBridge.runtime;
31 |
32 | if (jsiRuntime == nil) return @false;
33 |
34 | webassembly::install(*(facebook::jsi::Runtime *)jsiRuntime);
35 |
36 | return @true;
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/react-native-webassembly.podspec:
--------------------------------------------------------------------------------
1 | require "json"
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5 |
6 | Pod::Spec.new do |s|
7 | s.name = "react-native-webassembly"
8 | s.version = package["version"]
9 | s.summary = package["description"]
10 | s.homepage = package["homepage"]
11 | s.license = package["license"]
12 | s.authors = package["author"]
13 |
14 | s.platforms = { :ios => "11.0" }
15 | s.source = { :git => "https://github.com/cawfree/react-native-webassembly.git", :tag => "#{s.version}" }
16 |
17 | s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{h,cpp,c}"
18 |
19 | s.dependency "React-Core"
20 |
21 | s.pod_target_xcconfig = {
22 | "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
23 | "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
24 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
25 | "CLANG_CXX_LIBRARY" => "libc++"
26 | }
27 | s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
28 | s.dependency "React-Codegen"
29 | s.dependency "RCT-Folly"
30 | s.dependency "RCTRequired"
31 | s.dependency "RCTTypeSafety"
32 | s.dependency "ReactCommon/turbomodule/core"
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/example/src/hooks/useWasmUri.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as WebAssembly from 'react-native-webassembly';
3 | import type { WebassemblyInstantiateResult } from 'react-native-webassembly';
4 |
5 | import { fetchWasm } from '../utils';
6 |
7 | type State = Readonly<
8 | | { loading: true }
9 | | { loading: false; result: WebassemblyInstantiateResult }
10 | | { loading: false; error: Error }
11 | >;
12 |
13 | export function useWasmUri(
14 | uri: string,
15 | importObject: WebAssembly.WebAssemblyImportObject | undefined = undefined
16 | ): State {
17 | const [state, setState] = React.useState>({
18 | loading: true,
19 | });
20 |
21 | React.useEffect(
22 | () =>
23 | void (async () => {
24 | try {
25 | setState({
26 | loading: false,
27 | result: await WebAssembly.instantiate(
28 | await fetchWasm(uri),
29 | importObject
30 | ),
31 | });
32 | } catch (cause) {
33 | setState({
34 | loading: false,
35 | error: new Error(
36 | `Failed to instantiate "${uri}".`,
37 | cause as ErrorOptions
38 | ),
39 | });
40 | }
41 | })(),
42 | [uri, importObject]
43 | );
44 |
45 | return state;
46 | }
47 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-webassembly",
3 | "version": "0.3.4",
4 | "description": "⚛️ 🏎 WebAssembly for React Native JSI.",
5 | "main": "lib/commonjs/index",
6 | "module": "lib/module/index",
7 | "types": "lib/typescript/index.d.ts",
8 | "react-native": "src/index",
9 | "source": "src/index",
10 | "files": [
11 | "src",
12 | "lib",
13 | "android",
14 | "ios",
15 | "cpp",
16 | "app.plugin.js",
17 | "*.podspec",
18 | "!lib/typescript/example",
19 | "!ios/build",
20 | "!android/build",
21 | "!android/gradle",
22 | "!android/gradlew",
23 | "!android/gradlew.bat",
24 | "!android/local.properties",
25 | "!**/__tests__",
26 | "!**/__fixtures__",
27 | "!**/__mocks__",
28 | "!**/.*"
29 | ],
30 | "scripts": {
31 | "test": "jest",
32 | "typecheck": "tsc --noEmit",
33 | "lint": "eslint \"**/*.{js,ts,tsx}\"",
34 | "prepack": "bob build",
35 | "build": "yarn prepack",
36 | "release": "release-it",
37 | "example": "yarn --cwd example",
38 | "bootstrap": "yarn example && yarn install && yarn example pods",
39 | "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build"
40 | },
41 | "keywords": [
42 | "react-native",
43 | "ios",
44 | "android"
45 | ],
46 | "repository": "https://github.com/cawfree/react-native-webassembly",
47 | "author": "cawfree (https://github.com/cawfree)",
48 | "license": "MIT",
49 | "bugs": {
50 | "url": "https://github.com/cawfree/react-native-webassembly/issues"
51 | },
52 | "homepage": "https://github.com/cawfree/react-native-webassembly#readme",
53 | "publishConfig": {
54 | "registry": "https://registry.npmjs.org/"
55 | },
56 | "devDependencies": {
57 | "@commitlint/config-conventional": "^17.0.2",
58 | "@evilmartians/lefthook": "^1.2.2",
59 | "@react-native-community/eslint-config": "^3.0.2",
60 | "@release-it/conventional-changelog": "^5.0.0",
61 | "@types/jest": "^28.1.2",
62 | "@types/react": "~17.0.21",
63 | "@types/react-native": "0.70.0",
64 | "commitlint": "^17.0.2",
65 | "del-cli": "^5.0.0",
66 | "eslint": "^8.4.1",
67 | "eslint-config-prettier": "^8.5.0",
68 | "eslint-plugin-prettier": "^4.0.0",
69 | "jest": "^28.1.1",
70 | "pod-install": "^0.1.0",
71 | "prettier": "^2.0.5",
72 | "react": "18.2.0",
73 | "react-native": "0.71.4",
74 | "react-native-builder-bob": "^0.20.4",
75 | "release-it": "^15.0.0",
76 | "typescript": "^4.5.2"
77 | },
78 | "resolutions": {
79 | "@types/react": "17.0.21"
80 | },
81 | "peerDependencies": {
82 | "react": "*",
83 | "react-native": "*"
84 | },
85 | "engines": {
86 | "node": ">= 16.0.0"
87 | },
88 | "packageManager": "^yarn@1.22.15",
89 | "jest": {
90 | "preset": "react-native",
91 | "modulePathIgnorePatterns": [
92 | "/example/node_modules",
93 | "/lib/"
94 | ]
95 | },
96 | "commitlint": {
97 | "extends": [
98 | "@commitlint/config-conventional"
99 | ]
100 | },
101 | "release-it": {
102 | "git": {
103 | "commitMessage": "chore: release ${version}",
104 | "tagName": "v${version}"
105 | },
106 | "npm": {
107 | "publish": true
108 | },
109 | "github": {
110 | "release": true
111 | },
112 | "plugins": {
113 | "@release-it/conventional-changelog": {
114 | "preset": "angular"
115 | }
116 | }
117 | },
118 | "eslintConfig": {
119 | "root": true,
120 | "extends": [
121 | "@react-native-community",
122 | "prettier"
123 | ],
124 | "rules": {
125 | "prettier/prettier": [
126 | "error",
127 | {
128 | "quoteProps": "consistent",
129 | "singleQuote": true,
130 | "tabWidth": 2,
131 | "trailingComma": "es5",
132 | "useTabs": false
133 | }
134 | ]
135 | }
136 | },
137 | "eslintIgnore": [
138 | "node_modules/",
139 | "lib/"
140 | ],
141 | "prettier": {
142 | "quoteProps": "consistent",
143 | "singleQuote": true,
144 | "tabWidth": 2,
145 | "trailingComma": "es5",
146 | "useTabs": false
147 | },
148 | "react-native-builder-bob": {
149 | "source": "src",
150 | "output": "lib",
151 | "targets": [
152 | "commonjs",
153 | "module",
154 | [
155 | "typescript",
156 | {
157 | "project": "tsconfig.build.json"
158 | }
159 | ]
160 | ]
161 | },
162 | "codegenConfig": {
163 | "name": "RNWebassemblySpec",
164 | "type": "modules",
165 | "jsSrcsDir": "src"
166 | },
167 | "dependencies": {
168 | "buffer": "^6.0.3",
169 | "nanoid": "3.3.4"
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
161 | );
162 | }
163 |
164 | const styles = StyleSheet.create({
165 | container: {
166 | flex: 1,
167 | alignItems: 'center',
168 | justifyContent: 'center',
169 | },
170 | });
171 |
--------------------------------------------------------------------------------
/cpp/m3_bind.c:
--------------------------------------------------------------------------------
1 | //
2 | // m3_bind.c
3 | //
4 | // Created by Steven Massey on 4/29/19.
5 | // Copyright © 2019 Steven Massey. All rights reserved.
6 | //
7 |
8 | #include "m3_env.h"
9 | #include "m3_exception.h"
10 | #include "m3_info.h"
11 |
12 |
13 | u8 ConvertTypeCharToTypeId (char i_code)
14 | {
15 | switch (i_code) {
16 | case 'v': return c_m3Type_none;
17 | case 'i': return c_m3Type_i32;
18 | case 'I': return c_m3Type_i64;
19 | case 'f': return c_m3Type_f32;
20 | case 'F': return c_m3Type_f64;
21 | case '*': return c_m3Type_i32;
22 | }
23 | return c_m3Type_unknown;
24 | }
25 |
26 | M3Result SignatureToFuncType (IM3FuncType * o_functionType, ccstr_t i_signature)
27 | {
28 | IM3FuncType funcType = NULL;
29 |
30 | _try {
31 | if (not o_functionType)
32 | _throw ("null function type");
33 |
34 | if (not i_signature)
35 | _throw ("null function signature");
36 |
37 | cstr_t sig = i_signature;
38 |
39 | size_t maxNumTypes = strlen (i_signature);
40 |
41 | // assume min signature is "()"
42 | _throwif (m3Err_malformedFunctionSignature, maxNumTypes < 2);
43 | maxNumTypes -= 2;
44 |
45 | _throwif (m3Err_tooManyArgsRets, maxNumTypes > 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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | const { Image, NativeModules } = require('react-native');
2 | const { Buffer } = require('buffer');
3 | const { nanoid } = require('nanoid/non-secure');
4 |
5 | type InstantiateCallbackResult = {
6 | readonly result: number;
7 | readonly buffer?: ArrayBuffer;
8 | };
9 |
10 | type InstantiateParamsCallbackParams = {
11 | readonly module: string;
12 | readonly func: string;
13 | readonly args: readonly string[];
14 | };
15 |
16 | type InstantiateParamsCallback = (
17 | params: InstantiateParamsCallbackParams
18 | ) => number | void;
19 |
20 | type InstantiateParams = {
21 | readonly iid: string;
22 | readonly bufferSource: string;
23 | readonly stackSizeInBytes: number;
24 | readonly callback: InstantiateParamsCallback;
25 | };
26 |
27 | type InvokeParams = {
28 | readonly iid: string;
29 | readonly func: string;
30 | readonly args: readonly string[];
31 | };
32 |
33 | // @ts-expect-error synthesized
34 | const reactNativeWebAssembly: {
35 | readonly RNWebassembly_instantiate: (
36 | params: InstantiateParams
37 | ) => InstantiateCallbackResult;
38 | readonly RNWebassembly_invoke: (params: InvokeParams) => readonly string[];
39 | } = global;
40 |
41 | if (
42 | typeof reactNativeWebAssembly.RNWebassembly_instantiate !== 'function' &&
43 | !NativeModules.Webassembly?.install?.()
44 | )
45 | throw new Error('Unable to bind Webassembly to React Native JSI.');
46 |
47 | export type WebassemblyInstance = {
48 | readonly exports: Exports;
49 | };
50 |
51 | type WebAssemblyMemoryParams = {
52 | readonly initial: number;
53 | };
54 |
55 | export class Memory {
56 | readonly __initial: WebAssemblyMemoryParams['initial'] | undefined;
57 |
58 | constructor(params: WebAssemblyMemoryParams) {
59 | this.__initial = params?.initial;
60 | }
61 | }
62 |
63 | export type WebAssemblyEnv = {
64 | readonly memory?: Memory;
65 | };
66 |
67 | const DEFAULT_STACK_SIZE_IN_BYTES = 8192;
68 |
69 | const DEFAULT_MEMORY = new Memory({
70 | initial: DEFAULT_STACK_SIZE_IN_BYTES,
71 | });
72 |
73 | export type Imports = Record;
74 |
75 | type ImportsMap = Omit<
76 | {
77 | readonly [key: string]: Imports | WebAssemblyEnv;
78 | },
79 | 'env'
80 | >;
81 |
82 | export type WebAssemblyImportObject = ImportsMap & {
83 | readonly env?: WebAssemblyEnv;
84 | };
85 |
86 | type WebAssemblyDefaultExports = {
87 | readonly memory?: ArrayBuffer;
88 | };
89 |
90 | export type WebassemblyInstantiateResult = {
91 | readonly instance: WebassemblyInstance;
92 | };
93 |
94 | const fetchRequireAsBase64 = async (moduleId: number): Promise => {
95 | const maybeAssetSource = Image.resolveAssetSource(moduleId);
96 |
97 | const maybeUri = maybeAssetSource?.uri;
98 |
99 | if (typeof maybeUri !== 'string' || !maybeUri.length)
100 | throw new Error(
101 | `Expected non-empty string uri, encountered "${String(maybeUri)}".`
102 | );
103 |
104 | const base64EncodedString = String(
105 | await new Promise(async (resolve, reject) => {
106 | const reader = new FileReader();
107 | reader.onload = () => resolve(reader.result);
108 | reader.onerror = reject;
109 | reader.readAsDataURL(await (await fetch(maybeUri)).blob());
110 | })
111 | );
112 |
113 | const maybeBase64EncodedString = base64EncodedString
114 | .substring(base64EncodedString.indexOf(','))
115 | .slice(1);
116 |
117 | if (
118 | typeof maybeBase64EncodedString !== 'string' ||
119 | !maybeBase64EncodedString.length
120 | )
121 | throw new Error(
122 | `Expected non-empty string base64EncodedString, encountered "${maybeBase64EncodedString}".`
123 | );
124 |
125 | return maybeBase64EncodedString;
126 | };
127 |
128 | // https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate
129 | export async function instantiate(
130 | bufferSource: Uint8Array | ArrayBuffer | number,
131 | maybeImportObject: WebAssemblyImportObject | undefined = undefined
132 | ): Promise> {
133 | const iid = nanoid();
134 |
135 | const importObject = maybeImportObject || {};
136 | const { env: maybeEnv } = importObject;
137 |
138 | const memory = maybeEnv?.memory || DEFAULT_MEMORY;
139 |
140 | const stackSizeInBytes = memory?.__initial ?? DEFAULT_STACK_SIZE_IN_BYTES;
141 |
142 | const bufferSourceBase64 =
143 | typeof bufferSource === 'number'
144 | ? await fetchRequireAsBase64(bufferSource)
145 | : Buffer.from(bufferSource).toString('base64');
146 |
147 | const {
148 | result: instanceResult,
149 | buffer: maybeBuffer,
150 | }: InstantiateCallbackResult =
151 | reactNativeWebAssembly.RNWebassembly_instantiate({
152 | iid,
153 | bufferSource: bufferSourceBase64,
154 | stackSizeInBytes,
155 | callback: ({ func, args, module }) => {
156 | const maybeModule = importObject[module];
157 |
158 | if (!maybeModule)
159 | throw new Error(
160 | `[WebAssembly]: Tried to invoke a function belonging to module "${module}", but this was not defined.`
161 | );
162 |
163 | // @ts-ignore
164 | const maybeFunction = maybeModule?.[func];
165 |
166 | if (!maybeFunction)
167 | throw new Error(
168 | `[WebAssembly]: Tried to invoke a function "${func}" belonging to module "${module}", but it was not defined.`
169 | );
170 |
171 | return maybeFunction(...args.map(parseFloat));
172 | },
173 | });
174 |
175 | if (instanceResult !== 0)
176 | throw new Error(`Failed to instantiate WebAssembly. (${instanceResult})`);
177 |
178 | const exports = new Proxy({} as Exports, {
179 | get(_, exportName) {
180 | if (typeof exportName !== 'string')
181 | throw new Error(`Expected string, encountered ${typeof exportName}.`);
182 |
183 | if (exportName === 'memory') return maybeBuffer;
184 |
185 | return (...args: readonly number[]) => {
186 | const res = reactNativeWebAssembly.RNWebassembly_invoke({
187 | iid,
188 | func: exportName,
189 | args: args.map((e) => e.toString()),
190 | });
191 |
192 | if (!res.length) return undefined;
193 |
194 | const num = res.map(parseFloat);
195 |
196 | // TODO: This is incorrect. We need to check if the return type is truly
197 | // a scalar or not.
198 | if (res.length !== 1) return num;
199 |
200 | return num[0];
201 | };
202 | },
203 | });
204 |
205 | return { instance: { exports } };
206 | }
207 |
--------------------------------------------------------------------------------
/example/src/hooks/useWasmCircomRuntime.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as WebAssembly from 'react-native-webassembly';
3 |
4 | import { useWasmUri } from './useWasmUri';
5 |
6 | type Circom = {
7 | readonly getVersion: () => number;
8 | readonly getFieldNumLen32: () => number;
9 | readonly getRawPrime: () => number;
10 | readonly getWitnessSize: () => number;
11 | readonly init: (shouldSanityCheck: number) => undefined;
12 | readonly getInputSignalSize: (a: number, b: number) => number;
13 | readonly readSharedRWMemory: (a: number) => number;
14 | readonly writeSharedRWMemory: (a: number, b: number) => undefined;
15 | readonly setInputSignal: (a: number, b: number, c: number) => undefined;
16 | readonly getWitness: (a: number) => undefined;
17 | };
18 |
19 | // https://github.com/cawfree/zk-assets/tree/main/Circuits/01
20 | type Circuits_01_Input = {
21 | readonly a: number;
22 | readonly b: number;
23 | };
24 |
25 | function fnvHash(str: string) {
26 | const uint64_max = BigInt(18446744073709551616);
27 | let hash = BigInt('0xCBF29CE484222325');
28 | for (var i = 0; i < str.length; i += 1) {
29 | hash ^= BigInt(str[i]!.charCodeAt(0));
30 | hash *= BigInt(0x100000001b3);
31 | hash %= uint64_max;
32 | }
33 | let shash = hash.toString(16);
34 | let n = 16 - shash.length;
35 | shash = '0'.repeat(n).concat(shash);
36 | return shash;
37 | }
38 |
39 | function flatArray(a: unknown) {
40 | if (Array.isArray(a)) return [...a];
41 |
42 | return [a];
43 | }
44 |
45 | function fromArray32(arr: Uint32Array) {
46 | //returns a BigInt
47 | var res = BigInt(0);
48 | const radix = BigInt(0x100000000);
49 | for (let i = 0; i < arr.length; i++) {
50 | res = res * radix + BigInt(arr[i]!);
51 | }
52 | return res;
53 | }
54 |
55 | function toArray32(rem: bigint, size: number) {
56 | const res = [];
57 | const radix = BigInt(0x100000000);
58 | while (rem) {
59 | res.unshift(Number(rem % radix));
60 | rem = rem / radix;
61 | }
62 | if (size) {
63 | var i = size - res.length;
64 | while (i > 0) {
65 | res.unshift(0);
66 | i--;
67 | }
68 | }
69 | return res;
70 | }
71 |
72 | function normalize(n: bigint, prime: bigint) {
73 | let res = BigInt(n) % prime;
74 | if (res < 0) res += prime;
75 | return res;
76 | }
77 |
78 | const calculateWTNSBinInternal = ({
79 | circom,
80 | input,
81 | sanityCheck,
82 | prime,
83 | }: {
84 | readonly circom: Circom;
85 | readonly input: Record;
86 | readonly sanityCheck: number;
87 | readonly prime: bigint;
88 | }) => {
89 | circom.init(sanityCheck);
90 |
91 | const n32 = circom.getFieldNumLen32();
92 |
93 | for (const key of Object.keys(input)) {
94 | const h = fnvHash(key);
95 | const hMSB = parseInt(h.slice(0, 8), 16);
96 | const hLSB = parseInt(h.slice(8, 16), 16);
97 | const fArr = flatArray(input[key]);
98 | const signalSize = circom.getInputSignalSize(hMSB, hLSB);
99 |
100 | if (signalSize < 0) throw new Error(`Signal "${key}" not found!`);
101 |
102 | if (fArr.length < signalSize)
103 | throw new Error(`Not enough values for input signal "${key}"!`);
104 |
105 | if (fArr.length > signalSize)
106 | throw new Error(`Too many values for input signal "${key}"!`);
107 |
108 | for (let i = 0; i < fArr.length; i += 1) {
109 | const arrFr = toArray32(normalize(fArr[i], prime), n32);
110 |
111 | for (let j = 0; j < n32; j += 1) {
112 | circom.writeSharedRWMemory(j, Number(arrFr[n32 - 1 - j]));
113 | }
114 |
115 | circom.setInputSignal(hMSB, hLSB, i);
116 | }
117 | }
118 | };
119 |
120 | export function useWasmCircomRuntime() {
121 | const wasm = useWasmUri(
122 | 'https://github.com/cawfree/zk-assets/raw/main/Circuits/01/.wasm',
123 | React.useMemo(
124 | () => ({
125 | env: {
126 | // https://github.com/iden3/circom_runtime/blob/f9de6f7d6efe521b5df6775258779ec9032b5830/js/witness_calculator.js#L27
127 | memory: new WebAssembly.Memory({ initial: 32767 }),
128 | },
129 | runtime: {
130 | exceptionHandler(value: number) {
131 | console.warn('got exception', value);
132 | },
133 | },
134 | }),
135 | []
136 | )
137 | );
138 |
139 | const result = 'result' in wasm ? wasm.result : undefined;
140 | const error = 'error' in wasm ? wasm.error : undefined;
141 |
142 | const calculateWTNSBin = React.useCallback(
143 | (input: Circuits_01_Input, sanityCheck: number = 0) => {
144 | if (!result) throw new Error('Not ready to calculate.');
145 |
146 | const circom: Circom = result.instance.exports;
147 |
148 | const n32 = circom.getFieldNumLen32();
149 | const witnessSize = circom.getWitnessSize();
150 |
151 | circom.getRawPrime();
152 |
153 | const arr = new Uint32Array(n32);
154 |
155 | for (let i = 0; i < n32; i += 1) {
156 | arr[n32 - 1 - i] = circom.readSharedRWMemory(i);
157 | }
158 |
159 | const prime = fromArray32(arr);
160 |
161 | calculateWTNSBinInternal({ circom, input, sanityCheck, prime });
162 |
163 | const len = witnessSize * n32 + n32 + 11;
164 |
165 | const buff32 = new Uint32Array(len);
166 | const buff = new Uint8Array(buff32.buffer);
167 |
168 | //"wtns"
169 | buff[0] = 'w'.charCodeAt(0);
170 | buff[1] = 't'.charCodeAt(0);
171 | buff[2] = 'n'.charCodeAt(0);
172 | buff[3] = 's'.charCodeAt(0);
173 |
174 | //version 2
175 | buff32[1] = 2;
176 |
177 | //number of sections: 2
178 | buff32[2] = 2;
179 |
180 | //id section 1
181 | buff32[3] = 1;
182 |
183 | const n8 = n32 * 4;
184 |
185 | //id section 1 length in 64bytes
186 | const idSection1length = 8 + n8;
187 | const idSection1lengthHex = idSection1length.toString(16);
188 |
189 | buff32[4] = parseInt(idSection1lengthHex.slice(0, 8), 16);
190 | buff32[5] = parseInt(idSection1lengthHex.slice(8, 16), 16);
191 |
192 | //this.n32
193 | buff32[6] = n8;
194 |
195 | circom.getRawPrime();
196 |
197 | var pos = 7;
198 |
199 | for (let j = 0; j < n32; j += 1) {
200 | buff32[pos + j] = circom.readSharedRWMemory(j);
201 | }
202 |
203 | pos += n32;
204 |
205 | // witness size
206 | buff32[pos] = witnessSize;
207 | pos++;
208 |
209 | //id section 2
210 | buff32[pos] = 2;
211 | pos++;
212 |
213 | // section 2 length
214 | const idSection2length = n8 * witnessSize;
215 | const idSection2lengthHex = idSection2length.toString(16);
216 | buff32[pos] = parseInt(idSection2lengthHex.slice(0, 8), 16);
217 | buff32[pos + 1] = parseInt(idSection2lengthHex.slice(8, 16), 16);
218 |
219 | pos += 2;
220 | for (let i = 0; i < witnessSize; i += 1) {
221 | circom.getWitness(i);
222 | for (let j = 0; j < n32; j += 1) {
223 | buff32[pos + j] = circom.readSharedRWMemory(j);
224 | }
225 | pos += n32;
226 | }
227 |
228 | return buff;
229 | },
230 | [result]
231 | );
232 |
233 | return { calculateWTNSBin, error };
234 | }
235 |
--------------------------------------------------------------------------------
/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_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_api_tracer.c:
--------------------------------------------------------------------------------
1 | //
2 | // m3_api_tracer.c
3 | //
4 | // Created by Volodymyr Shymanskyy on 02/18/20.
5 | // Copyright © 2020 Volodymyr Shymanskyy. All rights reserved.
6 | //
7 |
8 | #include "m3_api_tracer.h"
9 |
10 | #include "m3_env.h"
11 | #include "m3_exception.h"
12 |
13 | #if defined(d_m3HasTracer)
14 |
15 |
16 | static FILE* trace = NULL;
17 |
18 | m3ApiRawFunction(m3_env_log_execution)
19 | {
20 | m3ApiGetArg (uint32_t, id)
21 | fprintf(trace, "exec;%d\n", id);
22 | m3ApiSuccess();
23 | }
24 |
25 | m3ApiRawFunction(m3_env_log_exec_enter)
26 | {
27 | m3ApiGetArg (uint32_t, id)
28 | m3ApiGetArg (uint32_t, func)
29 | fprintf(trace, "enter;%d;%d\n", id, func);
30 | m3ApiSuccess();
31 | }
32 |
33 | m3ApiRawFunction(m3_env_log_exec_exit)
34 | {
35 | m3ApiGetArg (uint32_t, id)
36 | m3ApiGetArg (uint32_t, func)
37 | fprintf(trace, "exit;%d;%d\n", id, func);
38 | m3ApiSuccess();
39 | }
40 |
41 | m3ApiRawFunction(m3_env_log_exec_loop)
42 | {
43 | m3ApiGetArg (uint32_t, id)
44 | fprintf(trace, "loop;%d\n", id);
45 | m3ApiSuccess();
46 | }
47 |
48 | m3ApiRawFunction(m3_env_load_ptr)
49 | {
50 | m3ApiReturnType (uint32_t)
51 | m3ApiGetArg (uint32_t, id)
52 | m3ApiGetArg (uint32_t, align)
53 | m3ApiGetArg (uint32_t, offset)
54 | m3ApiGetArg (uint32_t, address)
55 | fprintf(trace, "load ptr;%d;%d;%d;%d\n", id, align, offset, address);
56 | m3ApiReturn(address);
57 | }
58 |
59 | m3ApiRawFunction(m3_env_store_ptr)
60 | {
61 | m3ApiReturnType (uint32_t)
62 | m3ApiGetArg (uint32_t, id)
63 | m3ApiGetArg (uint32_t, align)
64 | m3ApiGetArg (uint32_t, offset)
65 | m3ApiGetArg (uint32_t, address)
66 | fprintf(trace, "store ptr;%d;%d;%d;%d\n", id, align, offset, address);
67 | m3ApiReturn(address);
68 | }
69 |
70 |
71 | #define d_m3TraceMemory(FUNC, NAME, TYPE, FMT) \
72 | m3ApiRawFunction(m3_env_##FUNC) \
73 | { \
74 | m3ApiReturnType (TYPE) \
75 | m3ApiGetArg (uint32_t, id) \
76 | m3ApiGetArg (TYPE, val) \
77 | fprintf(trace, NAME ";%d;" FMT "\n", id, val); \
78 | m3ApiReturn(val); \
79 | }
80 |
81 | d_m3TraceMemory( load_val_i32, "load i32", int32_t, "%" PRIi32)
82 | d_m3TraceMemory(store_val_i32, "store i32", int32_t, "%" PRIi32)
83 | d_m3TraceMemory( load_val_i64, "load i64", int64_t, "%" PRIi64)
84 | d_m3TraceMemory(store_val_i64, "store i64", int64_t, "%" PRIi64)
85 | d_m3TraceMemory( load_val_f32, "load f32", float, "%" PRIf32)
86 | d_m3TraceMemory(store_val_f32, "store f32", float, "%" PRIf32)
87 | d_m3TraceMemory( load_val_f64, "load f64", double, "%" PRIf64)
88 | d_m3TraceMemory(store_val_f64, "store f64", double, "%" PRIf64)
89 |
90 |
91 | #define d_m3TraceLocal(FUNC, NAME, TYPE, FMT) \
92 | m3ApiRawFunction(m3_env_##FUNC) \
93 | { \
94 | m3ApiReturnType (TYPE) \
95 | m3ApiGetArg (uint32_t, id) \
96 | m3ApiGetArg (uint32_t, local) \
97 | m3ApiGetArg (TYPE, val) \
98 | fprintf(trace, NAME ";%d;%d;" FMT "\n", id, local, val); \
99 | m3ApiReturn(val); \
100 | }
101 |
102 |
103 | d_m3TraceLocal(get_i32, "get i32", int32_t, "%" PRIi32)
104 | d_m3TraceLocal(set_i32, "set i32", int32_t, "%" PRIi32)
105 | d_m3TraceLocal(get_i64, "get i64", int64_t, "%" PRIi64)
106 | d_m3TraceLocal(set_i64, "set i64", int64_t, "%" PRIi64)
107 | d_m3TraceLocal(get_f32, "get f32", float, "%" PRIf32)
108 | d_m3TraceLocal(set_f32, "set f32", float, "%" PRIf32)
109 | d_m3TraceLocal(get_f64, "get f64", double, "%" PRIf64)
110 | d_m3TraceLocal(set_f64, "set f64", double, "%" PRIf64)
111 |
112 |
113 | static
114 | M3Result SuppressLookupFailure(M3Result i_result)
115 | {
116 | if (i_result == m3Err_none) {
117 | // If any trace function is found in the module, open the trace file
118 | if (!trace) {
119 | trace = fopen ("wasm3_trace.csv","w");
120 | }
121 | } else if (i_result == m3Err_functionLookupFailed) {
122 | i_result = m3Err_none;
123 | }
124 | return i_result;
125 | }
126 |
127 |
128 | M3Result m3_LinkTracer (IM3Module module)
129 | {
130 | M3Result result = m3Err_none;
131 |
132 | const char* env = "env";
133 |
134 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "log_execution", "v(i)", &m3_env_log_execution)));
135 |
136 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "log_exec_enter", "v(ii)", &m3_env_log_exec_enter)));
137 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "log_exec_exit", "v(ii)", &m3_env_log_exec_exit)));
138 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "log_exec_loop", "v(i)", &m3_env_log_exec_loop)));
139 |
140 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "load_ptr", "i(iiii)", &m3_env_load_ptr)));
141 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "store_ptr", "i(iiii)", &m3_env_store_ptr)));
142 |
143 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "load_val_i32", "i(ii)", &m3_env_load_val_i32)));
144 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "load_val_i64", "I(iI)", &m3_env_load_val_i64)));
145 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "load_val_f32", "f(if)", &m3_env_load_val_f32)));
146 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "load_val_f64", "F(iF)", &m3_env_load_val_f64)));
147 |
148 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "store_val_i32", "i(ii)", &m3_env_store_val_i32)));
149 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "store_val_i64", "I(iI)", &m3_env_store_val_i64)));
150 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "store_val_f32", "f(if)", &m3_env_store_val_f32)));
151 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "store_val_f64", "F(iF)", &m3_env_store_val_f64)));
152 |
153 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "get_i32", "i(iii)", &m3_env_get_i32)));
154 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "get_i64", "I(iiI)", &m3_env_get_i64)));
155 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "get_f32", "f(iif)", &m3_env_get_f32)));
156 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "get_f64", "F(iiF)", &m3_env_get_f64)));
157 |
158 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "set_i32", "i(iii)", &m3_env_set_i32)));
159 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "set_i64", "I(iiI)", &m3_env_set_i64)));
160 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "set_f32", "f(iif)", &m3_env_set_f32)));
161 | _ (SuppressLookupFailure (m3_LinkRawFunction (module, env, "set_f64", "F(iiF)", &m3_env_set_f64)));
162 |
163 | _catch:
164 | return result;
165 | }
166 |
167 | #endif // d_m3HasTracer
168 |
169 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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= 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------