├── .editorconfig ├── .gitattributes ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ └── ci.yml ├── .gitignore ├── .nvmrc ├── .watchmanconfig ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ └── plugin-workspace-tools.cjs └── releases │ └── yarn-3.6.1.cjs ├── .yarnrc.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── android ├── CMakeLists.txt ├── build.gradle ├── cpp-adapter.cpp ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ ├── AndroidManifestNew.xml │ └── java │ │ └── com │ │ └── callstack │ │ └── reactnativerapier │ │ ├── ReactNativeRapierModule.kt │ │ └── ReactNativeRapierPackage.kt │ ├── newarch │ └── ReactNativeRapierSpec.kt │ └── oldarch │ └── ReactNativeRapierSpec.kt ├── babel.config.js ├── cpp ├── gen │ ├── jsi-exports-bridge.cpp │ ├── jsi-exports-bridge.h │ ├── jsi-imports-bridge.cpp │ ├── jsi-imports-bridge.h │ ├── rapier_wasm3d_bg.c │ └── rapier_wasm3d_bg.h ├── macros.h ├── react-native-rapier.cpp ├── react-native-rapier.h └── wasm-rt │ ├── wasm-rt-exceptions.c │ ├── wasm-rt-exceptions.h │ ├── wasm-rt-impl-tableops.inc │ ├── wasm-rt-impl.c │ ├── wasm-rt-impl.h │ ├── wasm-rt-mem-impl-helper.inc │ ├── wasm-rt-mem-impl.c │ └── wasm-rt.h ├── example ├── .watchmanconfig ├── android │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── File.swift │ ├── Podfile │ ├── Podfile.lock │ ├── ReactNativeRapierExample-Bridging-Header.h │ └── ReactNativeRapierExample.xcworkspace │ │ └── contents.xcworkspacedata ├── metro.config.js ├── package.json ├── react-native.config.js └── src │ └── App.tsx ├── ios ├── ReactNativeRapier.h └── ReactNativeRapier.mm ├── lefthook.yml ├── package.json ├── react-native-rapier.podspec ├── react-native.config.js ├── src ├── NativeReactNativeRapier.ts ├── __tests__ │ └── index.test.tsx └── index.tsx ├── tsconfig.build.json ├── tsconfig.json ├── turbo.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Setup Node.js and install dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Setup Node.js 8 | uses: actions/setup-node@v3 9 | with: 10 | node-version-file: .nvmrc 11 | 12 | - name: Cache dependencies 13 | id: yarn-cache 14 | uses: actions/cache@v3 15 | with: 16 | path: | 17 | **/node_modules 18 | .yarn/install-state.gz 19 | key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }} 20 | restore-keys: | 21 | ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} 22 | ${{ runner.os }}-yarn- 23 | 24 | - name: Install dependencies 25 | if: steps.yarn-cache.outputs.cache-hit != 'true' 26 | run: yarn install --immutable 27 | shell: bash 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | merge_group: 10 | types: 11 | - checks_requested 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Setup 21 | uses: ./.github/actions/setup 22 | 23 | - name: Lint files 24 | run: yarn lint 25 | 26 | - name: Typecheck files 27 | run: yarn typecheck 28 | 29 | test: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v3 34 | 35 | - name: Setup 36 | uses: ./.github/actions/setup 37 | 38 | - name: Run unit tests 39 | run: yarn test --maxWorkers=2 --coverage 40 | 41 | build-library: 42 | runs-on: ubuntu-latest 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v3 46 | 47 | - name: Setup 48 | uses: ./.github/actions/setup 49 | 50 | - name: Build package 51 | run: yarn prepare 52 | 53 | build-android: 54 | # Disable android builds for now 55 | if: false 56 | runs-on: ubuntu-latest 57 | env: 58 | TURBO_CACHE_DIR: .turbo/android 59 | steps: 60 | - name: Checkout 61 | uses: actions/checkout@v3 62 | 63 | - name: Setup 64 | uses: ./.github/actions/setup 65 | 66 | - name: Cache turborepo for Android 67 | uses: actions/cache@v3 68 | with: 69 | path: ${{ env.TURBO_CACHE_DIR }} 70 | key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }} 71 | restore-keys: | 72 | ${{ runner.os }}-turborepo-android- 73 | 74 | - name: Check turborepo cache for Android 75 | run: | 76 | TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status") 77 | 78 | if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then 79 | echo "turbo_cache_hit=1" >> $GITHUB_ENV 80 | fi 81 | 82 | - name: Install JDK 83 | if: env.turbo_cache_hit != 1 84 | uses: actions/setup-java@v3 85 | with: 86 | distribution: 'zulu' 87 | java-version: '17' 88 | 89 | - name: Finalize Android SDK 90 | if: env.turbo_cache_hit != 1 91 | run: | 92 | /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" 93 | 94 | - name: Cache Gradle 95 | if: env.turbo_cache_hit != 1 96 | uses: actions/cache@v3 97 | with: 98 | path: | 99 | ~/.gradle/wrapper 100 | ~/.gradle/caches 101 | key: ${{ runner.os }}-gradle-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} 102 | restore-keys: | 103 | ${{ runner.os }}-gradle- 104 | 105 | - name: Build example for Android 106 | env: 107 | JAVA_OPTS: "-XX:MaxHeapSize=6g" 108 | run: | 109 | yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" 110 | 111 | build-ios: 112 | runs-on: macos-14 113 | env: 114 | TURBO_CACHE_DIR: .turbo/ios 115 | steps: 116 | - name: Checkout 117 | uses: actions/checkout@v3 118 | 119 | - name: Setup 120 | uses: ./.github/actions/setup 121 | 122 | - name: Cache turborepo for iOS 123 | uses: actions/cache@v3 124 | with: 125 | path: ${{ env.TURBO_CACHE_DIR }} 126 | key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }} 127 | restore-keys: | 128 | ${{ runner.os }}-turborepo-ios- 129 | 130 | - name: Check turborepo cache for iOS 131 | run: | 132 | TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status") 133 | 134 | if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then 135 | echo "turbo_cache_hit=1" >> $GITHUB_ENV 136 | fi 137 | 138 | - name: Cache cocoapods 139 | if: env.turbo_cache_hit != 1 140 | id: cocoapods-cache 141 | uses: actions/cache@v3 142 | with: 143 | path: | 144 | **/ios/Pods 145 | key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }} 146 | restore-keys: | 147 | ${{ runner.os }}-cocoapods- 148 | 149 | - name: Install cocoapods 150 | if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' 151 | run: | 152 | cd example/ios 153 | pod install 154 | env: 155 | NO_FLIPPER: 1 156 | 157 | - name: Build example for iOS 158 | run: | 159 | yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" 160 | -------------------------------------------------------------------------------- /.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 | example/ios/.xcode.env 47 | 48 | # Ruby 49 | example/vendor/ 50 | 51 | # node.js 52 | # 53 | node_modules/ 54 | npm-debug.log 55 | yarn-debug.log 56 | yarn-error.log 57 | 58 | # BUCK 59 | buck-out/ 60 | \.buckd/ 61 | android/app/libs 62 | android/keystores/debug.keystore 63 | 64 | # Yarn 65 | .yarn/* 66 | !.yarn/patches 67 | !.yarn/plugins 68 | !.yarn/releases 69 | !.yarn/sdks 70 | !.yarn/versions 71 | 72 | # Expo 73 | .expo/ 74 | 75 | # Turborepo 76 | .turbo/ 77 | 78 | # generated by bob 79 | lib/ 80 | 81 | # React Native Codegen 82 | ios/generated 83 | android/generated 84 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-workspace-tools", 5 | factory: function (require) { 6 | var plugin=(()=>{var yr=Object.create;var we=Object.defineProperty;var _r=Object.getOwnPropertyDescriptor;var Er=Object.getOwnPropertyNames;var br=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty;var W=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var q=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),Cr=(e,r)=>{for(var t in r)we(e,t,{get:r[t],enumerable:!0})},Je=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Er(r))!xr.call(e,s)&&s!==t&&we(e,s,{get:()=>r[s],enumerable:!(n=_r(r,s))||n.enumerable});return e};var Be=(e,r,t)=>(t=e!=null?yr(br(e)):{},Je(r||!e||!e.__esModule?we(t,"default",{value:e,enumerable:!0}):t,e)),wr=e=>Je(we({},"__esModule",{value:!0}),e);var ve=q(ee=>{"use strict";ee.isInteger=e=>typeof e=="number"?Number.isInteger(e):typeof e=="string"&&e.trim()!==""?Number.isInteger(Number(e)):!1;ee.find=(e,r)=>e.nodes.find(t=>t.type===r);ee.exceedsLimit=(e,r,t=1,n)=>n===!1||!ee.isInteger(e)||!ee.isInteger(r)?!1:(Number(r)-Number(e))/Number(t)>=n;ee.escapeNode=(e,r=0,t)=>{let n=e.nodes[r];!n||(t&&n.type===t||n.type==="open"||n.type==="close")&&n.escaped!==!0&&(n.value="\\"+n.value,n.escaped=!0)};ee.encloseBrace=e=>e.type!=="brace"?!1:e.commas>>0+e.ranges>>0===0?(e.invalid=!0,!0):!1;ee.isInvalidBrace=e=>e.type!=="brace"?!1:e.invalid===!0||e.dollar?!0:e.commas>>0+e.ranges>>0===0||e.open!==!0||e.close!==!0?(e.invalid=!0,!0):!1;ee.isOpenOrClose=e=>e.type==="open"||e.type==="close"?!0:e.open===!0||e.close===!0;ee.reduce=e=>e.reduce((r,t)=>(t.type==="text"&&r.push(t.value),t.type==="range"&&(t.type="text"),r),[]);ee.flatten=(...e)=>{let r=[],t=n=>{for(let s=0;s{"use strict";var tt=ve();rt.exports=(e,r={})=>{let t=(n,s={})=>{let i=r.escapeInvalid&&tt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c="";if(n.value)return(i||a)&&tt.isOpenOrClose(n)?"\\"+n.value:n.value;if(n.value)return n.value;if(n.nodes)for(let p of n.nodes)c+=t(p);return c};return t(e)}});var st=q((Vn,nt)=>{"use strict";nt.exports=function(e){return typeof e=="number"?e-e===0:typeof e=="string"&&e.trim()!==""?Number.isFinite?Number.isFinite(+e):isFinite(+e):!1}});var ht=q((Jn,pt)=>{"use strict";var at=st(),le=(e,r,t)=>{if(at(e)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(r===void 0||e===r)return String(e);if(at(r)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let n={relaxZeros:!0,...t};typeof n.strictZeros=="boolean"&&(n.relaxZeros=n.strictZeros===!1);let s=String(n.relaxZeros),i=String(n.shorthand),a=String(n.capture),c=String(n.wrap),p=e+":"+r+"="+s+i+a+c;if(le.cache.hasOwnProperty(p))return le.cache[p].result;let m=Math.min(e,r),h=Math.max(e,r);if(Math.abs(m-h)===1){let y=e+"|"+r;return n.capture?`(${y})`:n.wrap===!1?y:`(?:${y})`}let R=ft(e)||ft(r),f={min:e,max:r,a:m,b:h},$=[],_=[];if(R&&(f.isPadded=R,f.maxLen=String(f.max).length),m<0){let y=h<0?Math.abs(h):1;_=it(y,Math.abs(m),f,n),m=f.a=0}return h>=0&&($=it(m,h,f,n)),f.negatives=_,f.positives=$,f.result=Sr(_,$,n),n.capture===!0?f.result=`(${f.result})`:n.wrap!==!1&&$.length+_.length>1&&(f.result=`(?:${f.result})`),le.cache[p]=f,f.result};function Sr(e,r,t){let n=Pe(e,r,"-",!1,t)||[],s=Pe(r,e,"",!1,t)||[],i=Pe(e,r,"-?",!0,t)||[];return n.concat(i).concat(s).join("|")}function vr(e,r){let t=1,n=1,s=ut(e,t),i=new Set([r]);for(;e<=s&&s<=r;)i.add(s),t+=1,s=ut(e,t);for(s=ct(r+1,n)-1;e1&&c.count.pop(),c.count.push(h.count[0]),c.string=c.pattern+lt(c.count),a=m+1;continue}t.isPadded&&(R=Lr(m,t,n)),h.string=R+h.pattern+lt(h.count),i.push(h),a=m+1,c=h}return i}function Pe(e,r,t,n,s){let i=[];for(let a of e){let{string:c}=a;!n&&!ot(r,"string",c)&&i.push(t+c),n&&ot(r,"string",c)&&i.push(t+c)}return i}function $r(e,r){let t=[];for(let n=0;nr?1:r>e?-1:0}function ot(e,r,t){return e.some(n=>n[r]===t)}function ut(e,r){return Number(String(e).slice(0,-r)+"9".repeat(r))}function ct(e,r){return e-e%Math.pow(10,r)}function lt(e){let[r=0,t=""]=e;return t||r>1?`{${r+(t?","+t:"")}}`:""}function kr(e,r,t){return`[${e}${r-e===1?"":"-"}${r}]`}function ft(e){return/^-?(0+)\d/.test(e)}function Lr(e,r,t){if(!r.isPadded)return e;let n=Math.abs(r.maxLen-String(e).length),s=t.relaxZeros!==!1;switch(n){case 0:return"";case 1:return s?"0?":"0";case 2:return s?"0{0,2}":"00";default:return s?`0{0,${n}}`:`0{${n}}`}}le.cache={};le.clearCache=()=>le.cache={};pt.exports=le});var Ue=q((es,Et)=>{"use strict";var Or=W("util"),At=ht(),dt=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),Nr=e=>r=>e===!0?Number(r):String(r),Me=e=>typeof e=="number"||typeof e=="string"&&e!=="",Ae=e=>Number.isInteger(+e),De=e=>{let r=`${e}`,t=-1;if(r[0]==="-"&&(r=r.slice(1)),r==="0")return!1;for(;r[++t]==="0";);return t>0},Ir=(e,r,t)=>typeof e=="string"||typeof r=="string"?!0:t.stringify===!0,Br=(e,r,t)=>{if(r>0){let n=e[0]==="-"?"-":"";n&&(e=e.slice(1)),e=n+e.padStart(n?r-1:r,"0")}return t===!1?String(e):e},gt=(e,r)=>{let t=e[0]==="-"?"-":"";for(t&&(e=e.slice(1),r--);e.length{e.negatives.sort((a,c)=>ac?1:0),e.positives.sort((a,c)=>ac?1:0);let t=r.capture?"":"?:",n="",s="",i;return e.positives.length&&(n=e.positives.join("|")),e.negatives.length&&(s=`-(${t}${e.negatives.join("|")})`),n&&s?i=`${n}|${s}`:i=n||s,r.wrap?`(${t}${i})`:i},mt=(e,r,t,n)=>{if(t)return At(e,r,{wrap:!1,...n});let s=String.fromCharCode(e);if(e===r)return s;let i=String.fromCharCode(r);return`[${s}-${i}]`},Rt=(e,r,t)=>{if(Array.isArray(e)){let n=t.wrap===!0,s=t.capture?"":"?:";return n?`(${s}${e.join("|")})`:e.join("|")}return At(e,r,t)},yt=(...e)=>new RangeError("Invalid range arguments: "+Or.inspect(...e)),_t=(e,r,t)=>{if(t.strictRanges===!0)throw yt([e,r]);return[]},Mr=(e,r)=>{if(r.strictRanges===!0)throw new TypeError(`Expected step "${e}" to be a number`);return[]},Dr=(e,r,t=1,n={})=>{let s=Number(e),i=Number(r);if(!Number.isInteger(s)||!Number.isInteger(i)){if(n.strictRanges===!0)throw yt([e,r]);return[]}s===0&&(s=0),i===0&&(i=0);let a=s>i,c=String(e),p=String(r),m=String(t);t=Math.max(Math.abs(t),1);let h=De(c)||De(p)||De(m),R=h?Math.max(c.length,p.length,m.length):0,f=h===!1&&Ir(e,r,n)===!1,$=n.transform||Nr(f);if(n.toRegex&&t===1)return mt(gt(e,R),gt(r,R),!0,n);let _={negatives:[],positives:[]},y=T=>_[T<0?"negatives":"positives"].push(Math.abs(T)),E=[],S=0;for(;a?s>=i:s<=i;)n.toRegex===!0&&t>1?y(s):E.push(Br($(s,S),R,f)),s=a?s-t:s+t,S++;return n.toRegex===!0?t>1?Pr(_,n):Rt(E,null,{wrap:!1,...n}):E},Ur=(e,r,t=1,n={})=>{if(!Ae(e)&&e.length>1||!Ae(r)&&r.length>1)return _t(e,r,n);let s=n.transform||(f=>String.fromCharCode(f)),i=`${e}`.charCodeAt(0),a=`${r}`.charCodeAt(0),c=i>a,p=Math.min(i,a),m=Math.max(i,a);if(n.toRegex&&t===1)return mt(p,m,!1,n);let h=[],R=0;for(;c?i>=a:i<=a;)h.push(s(i,R)),i=c?i-t:i+t,R++;return n.toRegex===!0?Rt(h,null,{wrap:!1,options:n}):h},$e=(e,r,t,n={})=>{if(r==null&&Me(e))return[e];if(!Me(e)||!Me(r))return _t(e,r,n);if(typeof t=="function")return $e(e,r,1,{transform:t});if(dt(t))return $e(e,r,0,t);let s={...n};return s.capture===!0&&(s.wrap=!0),t=t||s.step||1,Ae(t)?Ae(e)&&Ae(r)?Dr(e,r,t,s):Ur(e,r,Math.max(Math.abs(t),1),s):t!=null&&!dt(t)?Mr(t,s):$e(e,r,1,t)};Et.exports=$e});var Ct=q((ts,xt)=>{"use strict";var Gr=Ue(),bt=ve(),qr=(e,r={})=>{let t=(n,s={})=>{let i=bt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c=i===!0||a===!0,p=r.escapeInvalid===!0?"\\":"",m="";if(n.isOpen===!0||n.isClose===!0)return p+n.value;if(n.type==="open")return c?p+n.value:"(";if(n.type==="close")return c?p+n.value:")";if(n.type==="comma")return n.prev.type==="comma"?"":c?n.value:"|";if(n.value)return n.value;if(n.nodes&&n.ranges>0){let h=bt.reduce(n.nodes),R=Gr(...h,{...r,wrap:!1,toRegex:!0});if(R.length!==0)return h.length>1&&R.length>1?`(${R})`:R}if(n.nodes)for(let h of n.nodes)m+=t(h,n);return m};return t(e)};xt.exports=qr});var vt=q((rs,St)=>{"use strict";var Kr=Ue(),wt=He(),he=ve(),fe=(e="",r="",t=!1)=>{let n=[];if(e=[].concat(e),r=[].concat(r),!r.length)return e;if(!e.length)return t?he.flatten(r).map(s=>`{${s}}`):r;for(let s of e)if(Array.isArray(s))for(let i of s)n.push(fe(i,r,t));else for(let i of r)t===!0&&typeof i=="string"&&(i=`{${i}}`),n.push(Array.isArray(i)?fe(s,i,t):s+i);return he.flatten(n)},Wr=(e,r={})=>{let t=r.rangeLimit===void 0?1e3:r.rangeLimit,n=(s,i={})=>{s.queue=[];let a=i,c=i.queue;for(;a.type!=="brace"&&a.type!=="root"&&a.parent;)a=a.parent,c=a.queue;if(s.invalid||s.dollar){c.push(fe(c.pop(),wt(s,r)));return}if(s.type==="brace"&&s.invalid!==!0&&s.nodes.length===2){c.push(fe(c.pop(),["{}"]));return}if(s.nodes&&s.ranges>0){let R=he.reduce(s.nodes);if(he.exceedsLimit(...R,r.step,t))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let f=Kr(...R,r);f.length===0&&(f=wt(s,r)),c.push(fe(c.pop(),f)),s.nodes=[];return}let p=he.encloseBrace(s),m=s.queue,h=s;for(;h.type!=="brace"&&h.type!=="root"&&h.parent;)h=h.parent,m=h.queue;for(let R=0;R{"use strict";Ht.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:` 7 | `,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Nt=q((ss,Ot)=>{"use strict";var jr=He(),{MAX_LENGTH:Tt,CHAR_BACKSLASH:Ge,CHAR_BACKTICK:Fr,CHAR_COMMA:Qr,CHAR_DOT:Xr,CHAR_LEFT_PARENTHESES:Zr,CHAR_RIGHT_PARENTHESES:Yr,CHAR_LEFT_CURLY_BRACE:zr,CHAR_RIGHT_CURLY_BRACE:Vr,CHAR_LEFT_SQUARE_BRACKET:kt,CHAR_RIGHT_SQUARE_BRACKET:Lt,CHAR_DOUBLE_QUOTE:Jr,CHAR_SINGLE_QUOTE:en,CHAR_NO_BREAK_SPACE:tn,CHAR_ZERO_WIDTH_NOBREAK_SPACE:rn}=$t(),nn=(e,r={})=>{if(typeof e!="string")throw new TypeError("Expected a string");let t=r||{},n=typeof t.maxLength=="number"?Math.min(Tt,t.maxLength):Tt;if(e.length>n)throw new SyntaxError(`Input length (${e.length}), exceeds max characters (${n})`);let s={type:"root",input:e,nodes:[]},i=[s],a=s,c=s,p=0,m=e.length,h=0,R=0,f,$={},_=()=>e[h++],y=E=>{if(E.type==="text"&&c.type==="dot"&&(c.type="text"),c&&c.type==="text"&&E.type==="text"){c.value+=E.value;return}return a.nodes.push(E),E.parent=a,E.prev=c,c=E,E};for(y({type:"bos"});h0){if(a.ranges>0){a.ranges=0;let E=a.nodes.shift();a.nodes=[E,{type:"text",value:jr(a)}]}y({type:"comma",value:f}),a.commas++;continue}if(f===Xr&&R>0&&a.commas===0){let E=a.nodes;if(R===0||E.length===0){y({type:"text",value:f});continue}if(c.type==="dot"){if(a.range=[],c.value+=f,c.type="range",a.nodes.length!==3&&a.nodes.length!==5){a.invalid=!0,a.ranges=0,c.type="text";continue}a.ranges++,a.args=[];continue}if(c.type==="range"){E.pop();let S=E[E.length-1];S.value+=c.value+f,c=S,a.ranges--;continue}y({type:"dot",value:f});continue}y({type:"text",value:f})}do if(a=i.pop(),a.type!=="root"){a.nodes.forEach(T=>{T.nodes||(T.type==="open"&&(T.isOpen=!0),T.type==="close"&&(T.isClose=!0),T.nodes||(T.type="text"),T.invalid=!0)});let E=i[i.length-1],S=E.nodes.indexOf(a);E.nodes.splice(S,1,...a.nodes)}while(i.length>0);return y({type:"eos"}),s};Ot.exports=nn});var Pt=q((as,Bt)=>{"use strict";var It=He(),sn=Ct(),an=vt(),on=Nt(),Z=(e,r={})=>{let t=[];if(Array.isArray(e))for(let n of e){let s=Z.create(n,r);Array.isArray(s)?t.push(...s):t.push(s)}else t=[].concat(Z.create(e,r));return r&&r.expand===!0&&r.nodupes===!0&&(t=[...new Set(t)]),t};Z.parse=(e,r={})=>on(e,r);Z.stringify=(e,r={})=>It(typeof e=="string"?Z.parse(e,r):e,r);Z.compile=(e,r={})=>(typeof e=="string"&&(e=Z.parse(e,r)),sn(e,r));Z.expand=(e,r={})=>{typeof e=="string"&&(e=Z.parse(e,r));let t=an(e,r);return r.noempty===!0&&(t=t.filter(Boolean)),r.nodupes===!0&&(t=[...new Set(t)]),t};Z.create=(e,r={})=>e===""||e.length<3?[e]:r.expand!==!0?Z.compile(e,r):Z.expand(e,r);Bt.exports=Z});var me=q((is,qt)=>{"use strict";var un=W("path"),se="\\\\/",Mt=`[^${se}]`,ie="\\.",cn="\\+",ln="\\?",Te="\\/",fn="(?=.)",Dt="[^/]",qe=`(?:${Te}|$)`,Ut=`(?:^|${Te})`,Ke=`${ie}{1,2}${qe}`,pn=`(?!${ie})`,hn=`(?!${Ut}${Ke})`,dn=`(?!${ie}{0,1}${qe})`,gn=`(?!${Ke})`,An=`[^.${Te}]`,mn=`${Dt}*?`,Gt={DOT_LITERAL:ie,PLUS_LITERAL:cn,QMARK_LITERAL:ln,SLASH_LITERAL:Te,ONE_CHAR:fn,QMARK:Dt,END_ANCHOR:qe,DOTS_SLASH:Ke,NO_DOT:pn,NO_DOTS:hn,NO_DOT_SLASH:dn,NO_DOTS_SLASH:gn,QMARK_NO_DOT:An,STAR:mn,START_ANCHOR:Ut},Rn={...Gt,SLASH_LITERAL:`[${se}]`,QMARK:Mt,STAR:`${Mt}*?`,DOTS_SLASH:`${ie}{1,2}(?:[${se}]|$)`,NO_DOT:`(?!${ie})`,NO_DOTS:`(?!(?:^|[${se}])${ie}{1,2}(?:[${se}]|$))`,NO_DOT_SLASH:`(?!${ie}{0,1}(?:[${se}]|$))`,NO_DOTS_SLASH:`(?!${ie}{1,2}(?:[${se}]|$))`,QMARK_NO_DOT:`[^.${se}]`,START_ANCHOR:`(?:^|[${se}])`,END_ANCHOR:`(?:[${se}]|$)`},yn={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};qt.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:yn,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:un.sep,extglobChars(e){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${e.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(e){return e===!0?Rn:Gt}}});var Re=q(Q=>{"use strict";var _n=W("path"),En=process.platform==="win32",{REGEX_BACKSLASH:bn,REGEX_REMOVE_BACKSLASH:xn,REGEX_SPECIAL_CHARS:Cn,REGEX_SPECIAL_CHARS_GLOBAL:wn}=me();Q.isObject=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);Q.hasRegexChars=e=>Cn.test(e);Q.isRegexChar=e=>e.length===1&&Q.hasRegexChars(e);Q.escapeRegex=e=>e.replace(wn,"\\$1");Q.toPosixSlashes=e=>e.replace(bn,"/");Q.removeBackslashes=e=>e.replace(xn,r=>r==="\\"?"":r);Q.supportsLookbehinds=()=>{let e=process.version.slice(1).split(".").map(Number);return e.length===3&&e[0]>=9||e[0]===8&&e[1]>=10};Q.isWindows=e=>e&&typeof e.windows=="boolean"?e.windows:En===!0||_n.sep==="\\";Q.escapeLast=(e,r,t)=>{let n=e.lastIndexOf(r,t);return n===-1?e:e[n-1]==="\\"?Q.escapeLast(e,r,n-1):`${e.slice(0,n)}\\${e.slice(n)}`};Q.removePrefix=(e,r={})=>{let t=e;return t.startsWith("./")&&(t=t.slice(2),r.prefix="./"),t};Q.wrapOutput=(e,r={},t={})=>{let n=t.contains?"":"^",s=t.contains?"":"$",i=`${n}(?:${e})${s}`;return r.negated===!0&&(i=`(?:^(?!${i}).*$)`),i}});var Yt=q((us,Zt)=>{"use strict";var Kt=Re(),{CHAR_ASTERISK:We,CHAR_AT:Sn,CHAR_BACKWARD_SLASH:ye,CHAR_COMMA:vn,CHAR_DOT:je,CHAR_EXCLAMATION_MARK:Fe,CHAR_FORWARD_SLASH:Xt,CHAR_LEFT_CURLY_BRACE:Qe,CHAR_LEFT_PARENTHESES:Xe,CHAR_LEFT_SQUARE_BRACKET:Hn,CHAR_PLUS:$n,CHAR_QUESTION_MARK:Wt,CHAR_RIGHT_CURLY_BRACE:Tn,CHAR_RIGHT_PARENTHESES:jt,CHAR_RIGHT_SQUARE_BRACKET:kn}=me(),Ft=e=>e===Xt||e===ye,Qt=e=>{e.isPrefix!==!0&&(e.depth=e.isGlobstar?1/0:1)},Ln=(e,r)=>{let t=r||{},n=e.length-1,s=t.parts===!0||t.scanToEnd===!0,i=[],a=[],c=[],p=e,m=-1,h=0,R=0,f=!1,$=!1,_=!1,y=!1,E=!1,S=!1,T=!1,L=!1,z=!1,I=!1,re=0,K,g,v={value:"",depth:0,isGlob:!1},k=()=>m>=n,l=()=>p.charCodeAt(m+1),H=()=>(K=g,p.charCodeAt(++m));for(;m0&&(B=p.slice(0,h),p=p.slice(h),R-=h),w&&_===!0&&R>0?(w=p.slice(0,R),o=p.slice(R)):_===!0?(w="",o=p):w=p,w&&w!==""&&w!=="/"&&w!==p&&Ft(w.charCodeAt(w.length-1))&&(w=w.slice(0,-1)),t.unescape===!0&&(o&&(o=Kt.removeBackslashes(o)),w&&T===!0&&(w=Kt.removeBackslashes(w)));let u={prefix:B,input:e,start:h,base:w,glob:o,isBrace:f,isBracket:$,isGlob:_,isExtglob:y,isGlobstar:E,negated:L,negatedExtglob:z};if(t.tokens===!0&&(u.maxDepth=0,Ft(g)||a.push(v),u.tokens=a),t.parts===!0||t.tokens===!0){let P;for(let b=0;b{"use strict";var ke=me(),Y=Re(),{MAX_LENGTH:Le,POSIX_REGEX_SOURCE:On,REGEX_NON_SPECIAL_CHARS:Nn,REGEX_SPECIAL_CHARS_BACKREF:In,REPLACEMENTS:zt}=ke,Bn=(e,r)=>{if(typeof r.expandRange=="function")return r.expandRange(...e,r);e.sort();let t=`[${e.join("-")}]`;try{new RegExp(t)}catch{return e.map(s=>Y.escapeRegex(s)).join("..")}return t},de=(e,r)=>`Missing ${e}: "${r}" - use "\\\\${r}" to match literal characters`,Vt=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");e=zt[e]||e;let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);let i={type:"bos",value:"",output:t.prepend||""},a=[i],c=t.capture?"":"?:",p=Y.isWindows(r),m=ke.globChars(p),h=ke.extglobChars(m),{DOT_LITERAL:R,PLUS_LITERAL:f,SLASH_LITERAL:$,ONE_CHAR:_,DOTS_SLASH:y,NO_DOT:E,NO_DOT_SLASH:S,NO_DOTS_SLASH:T,QMARK:L,QMARK_NO_DOT:z,STAR:I,START_ANCHOR:re}=m,K=A=>`(${c}(?:(?!${re}${A.dot?y:R}).)*?)`,g=t.dot?"":E,v=t.dot?L:z,k=t.bash===!0?K(t):I;t.capture&&(k=`(${k})`),typeof t.noext=="boolean"&&(t.noextglob=t.noext);let l={input:e,index:-1,start:0,dot:t.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:a};e=Y.removePrefix(e,l),s=e.length;let H=[],w=[],B=[],o=i,u,P=()=>l.index===s-1,b=l.peek=(A=1)=>e[l.index+A],V=l.advance=()=>e[++l.index]||"",J=()=>e.slice(l.index+1),X=(A="",O=0)=>{l.consumed+=A,l.index+=O},Ee=A=>{l.output+=A.output!=null?A.output:A.value,X(A.value)},mr=()=>{let A=1;for(;b()==="!"&&(b(2)!=="("||b(3)==="?");)V(),l.start++,A++;return A%2===0?!1:(l.negated=!0,l.start++,!0)},be=A=>{l[A]++,B.push(A)},oe=A=>{l[A]--,B.pop()},C=A=>{if(o.type==="globstar"){let O=l.braces>0&&(A.type==="comma"||A.type==="brace"),d=A.extglob===!0||H.length&&(A.type==="pipe"||A.type==="paren");A.type!=="slash"&&A.type!=="paren"&&!O&&!d&&(l.output=l.output.slice(0,-o.output.length),o.type="star",o.value="*",o.output=k,l.output+=o.output)}if(H.length&&A.type!=="paren"&&(H[H.length-1].inner+=A.value),(A.value||A.output)&&Ee(A),o&&o.type==="text"&&A.type==="text"){o.value+=A.value,o.output=(o.output||"")+A.value;return}A.prev=o,a.push(A),o=A},xe=(A,O)=>{let d={...h[O],conditions:1,inner:""};d.prev=o,d.parens=l.parens,d.output=l.output;let x=(t.capture?"(":"")+d.open;be("parens"),C({type:A,value:O,output:l.output?"":_}),C({type:"paren",extglob:!0,value:V(),output:x}),H.push(d)},Rr=A=>{let O=A.close+(t.capture?")":""),d;if(A.type==="negate"){let x=k;A.inner&&A.inner.length>1&&A.inner.includes("/")&&(x=K(t)),(x!==k||P()||/^\)+$/.test(J()))&&(O=A.close=`)$))${x}`),A.inner.includes("*")&&(d=J())&&/^\.[^\\/.]+$/.test(d)&&(O=A.close=`)${d})${x})`),A.prev.type==="bos"&&(l.negatedExtglob=!0)}C({type:"paren",extglob:!0,value:u,output:O}),oe("parens")};if(t.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(e)){let A=!1,O=e.replace(In,(d,x,M,j,G,Ie)=>j==="\\"?(A=!0,d):j==="?"?x?x+j+(G?L.repeat(G.length):""):Ie===0?v+(G?L.repeat(G.length):""):L.repeat(M.length):j==="."?R.repeat(M.length):j==="*"?x?x+j+(G?k:""):k:x?d:`\\${d}`);return A===!0&&(t.unescape===!0?O=O.replace(/\\/g,""):O=O.replace(/\\+/g,d=>d.length%2===0?"\\\\":d?"\\":"")),O===e&&t.contains===!0?(l.output=e,l):(l.output=Y.wrapOutput(O,l,r),l)}for(;!P();){if(u=V(),u==="\0")continue;if(u==="\\"){let d=b();if(d==="/"&&t.bash!==!0||d==="."||d===";")continue;if(!d){u+="\\",C({type:"text",value:u});continue}let x=/^\\+/.exec(J()),M=0;if(x&&x[0].length>2&&(M=x[0].length,l.index+=M,M%2!==0&&(u+="\\")),t.unescape===!0?u=V():u+=V(),l.brackets===0){C({type:"text",value:u});continue}}if(l.brackets>0&&(u!=="]"||o.value==="["||o.value==="[^")){if(t.posix!==!1&&u===":"){let d=o.value.slice(1);if(d.includes("[")&&(o.posix=!0,d.includes(":"))){let x=o.value.lastIndexOf("["),M=o.value.slice(0,x),j=o.value.slice(x+2),G=On[j];if(G){o.value=M+G,l.backtrack=!0,V(),!i.output&&a.indexOf(o)===1&&(i.output=_);continue}}}(u==="["&&b()!==":"||u==="-"&&b()==="]")&&(u=`\\${u}`),u==="]"&&(o.value==="["||o.value==="[^")&&(u=`\\${u}`),t.posix===!0&&u==="!"&&o.value==="["&&(u="^"),o.value+=u,Ee({value:u});continue}if(l.quotes===1&&u!=='"'){u=Y.escapeRegex(u),o.value+=u,Ee({value:u});continue}if(u==='"'){l.quotes=l.quotes===1?0:1,t.keepQuotes===!0&&C({type:"text",value:u});continue}if(u==="("){be("parens"),C({type:"paren",value:u});continue}if(u===")"){if(l.parens===0&&t.strictBrackets===!0)throw new SyntaxError(de("opening","("));let d=H[H.length-1];if(d&&l.parens===d.parens+1){Rr(H.pop());continue}C({type:"paren",value:u,output:l.parens?")":"\\)"}),oe("parens");continue}if(u==="["){if(t.nobracket===!0||!J().includes("]")){if(t.nobracket!==!0&&t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));u=`\\${u}`}else be("brackets");C({type:"bracket",value:u});continue}if(u==="]"){if(t.nobracket===!0||o&&o.type==="bracket"&&o.value.length===1){C({type:"text",value:u,output:`\\${u}`});continue}if(l.brackets===0){if(t.strictBrackets===!0)throw new SyntaxError(de("opening","["));C({type:"text",value:u,output:`\\${u}`});continue}oe("brackets");let d=o.value.slice(1);if(o.posix!==!0&&d[0]==="^"&&!d.includes("/")&&(u=`/${u}`),o.value+=u,Ee({value:u}),t.literalBrackets===!1||Y.hasRegexChars(d))continue;let x=Y.escapeRegex(o.value);if(l.output=l.output.slice(0,-o.value.length),t.literalBrackets===!0){l.output+=x,o.value=x;continue}o.value=`(${c}${x}|${o.value})`,l.output+=o.value;continue}if(u==="{"&&t.nobrace!==!0){be("braces");let d={type:"brace",value:u,output:"(",outputIndex:l.output.length,tokensIndex:l.tokens.length};w.push(d),C(d);continue}if(u==="}"){let d=w[w.length-1];if(t.nobrace===!0||!d){C({type:"text",value:u,output:u});continue}let x=")";if(d.dots===!0){let M=a.slice(),j=[];for(let G=M.length-1;G>=0&&(a.pop(),M[G].type!=="brace");G--)M[G].type!=="dots"&&j.unshift(M[G].value);x=Bn(j,t),l.backtrack=!0}if(d.comma!==!0&&d.dots!==!0){let M=l.output.slice(0,d.outputIndex),j=l.tokens.slice(d.tokensIndex);d.value=d.output="\\{",u=x="\\}",l.output=M;for(let G of j)l.output+=G.output||G.value}C({type:"brace",value:u,output:x}),oe("braces"),w.pop();continue}if(u==="|"){H.length>0&&H[H.length-1].conditions++,C({type:"text",value:u});continue}if(u===","){let d=u,x=w[w.length-1];x&&B[B.length-1]==="braces"&&(x.comma=!0,d="|"),C({type:"comma",value:u,output:d});continue}if(u==="/"){if(o.type==="dot"&&l.index===l.start+1){l.start=l.index+1,l.consumed="",l.output="",a.pop(),o=i;continue}C({type:"slash",value:u,output:$});continue}if(u==="."){if(l.braces>0&&o.type==="dot"){o.value==="."&&(o.output=R);let d=w[w.length-1];o.type="dots",o.output+=u,o.value+=u,d.dots=!0;continue}if(l.braces+l.parens===0&&o.type!=="bos"&&o.type!=="slash"){C({type:"text",value:u,output:R});continue}C({type:"dot",value:u,output:R});continue}if(u==="?"){if(!(o&&o.value==="(")&&t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("qmark",u);continue}if(o&&o.type==="paren"){let x=b(),M=u;if(x==="<"&&!Y.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(o.value==="("&&!/[!=<:]/.test(x)||x==="<"&&!/<([!=]|\w+>)/.test(J()))&&(M=`\\${u}`),C({type:"text",value:u,output:M});continue}if(t.dot!==!0&&(o.type==="slash"||o.type==="bos")){C({type:"qmark",value:u,output:z});continue}C({type:"qmark",value:u,output:L});continue}if(u==="!"){if(t.noextglob!==!0&&b()==="("&&(b(2)!=="?"||!/[!=<:]/.test(b(3)))){xe("negate",u);continue}if(t.nonegate!==!0&&l.index===0){mr();continue}}if(u==="+"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("plus",u);continue}if(o&&o.value==="("||t.regex===!1){C({type:"plus",value:u,output:f});continue}if(o&&(o.type==="bracket"||o.type==="paren"||o.type==="brace")||l.parens>0){C({type:"plus",value:u});continue}C({type:"plus",value:f});continue}if(u==="@"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){C({type:"at",extglob:!0,value:u,output:""});continue}C({type:"text",value:u});continue}if(u!=="*"){(u==="$"||u==="^")&&(u=`\\${u}`);let d=Nn.exec(J());d&&(u+=d[0],l.index+=d[0].length),C({type:"text",value:u});continue}if(o&&(o.type==="globstar"||o.star===!0)){o.type="star",o.star=!0,o.value+=u,o.output=k,l.backtrack=!0,l.globstar=!0,X(u);continue}let A=J();if(t.noextglob!==!0&&/^\([^?]/.test(A)){xe("star",u);continue}if(o.type==="star"){if(t.noglobstar===!0){X(u);continue}let d=o.prev,x=d.prev,M=d.type==="slash"||d.type==="bos",j=x&&(x.type==="star"||x.type==="globstar");if(t.bash===!0&&(!M||A[0]&&A[0]!=="/")){C({type:"star",value:u,output:""});continue}let G=l.braces>0&&(d.type==="comma"||d.type==="brace"),Ie=H.length&&(d.type==="pipe"||d.type==="paren");if(!M&&d.type!=="paren"&&!G&&!Ie){C({type:"star",value:u,output:""});continue}for(;A.slice(0,3)==="/**";){let Ce=e[l.index+4];if(Ce&&Ce!=="/")break;A=A.slice(3),X("/**",3)}if(d.type==="bos"&&P()){o.type="globstar",o.value+=u,o.output=K(t),l.output=o.output,l.globstar=!0,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&!j&&P()){l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=K(t)+(t.strictSlashes?")":"|$)"),o.value+=u,l.globstar=!0,l.output+=d.output+o.output,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&A[0]==="/"){let Ce=A[1]!==void 0?"|$":"";l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=`${K(t)}${$}|${$}${Ce})`,o.value+=u,l.output+=d.output+o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}if(d.type==="bos"&&A[0]==="/"){o.type="globstar",o.value+=u,o.output=`(?:^|${$}|${K(t)}${$})`,l.output=o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}l.output=l.output.slice(0,-o.output.length),o.type="globstar",o.output=K(t),o.value+=u,l.output+=o.output,l.globstar=!0,X(u);continue}let O={type:"star",value:u,output:k};if(t.bash===!0){O.output=".*?",(o.type==="bos"||o.type==="slash")&&(O.output=g+O.output),C(O);continue}if(o&&(o.type==="bracket"||o.type==="paren")&&t.regex===!0){O.output=u,C(O);continue}(l.index===l.start||o.type==="slash"||o.type==="dot")&&(o.type==="dot"?(l.output+=S,o.output+=S):t.dot===!0?(l.output+=T,o.output+=T):(l.output+=g,o.output+=g),b()!=="*"&&(l.output+=_,o.output+=_)),C(O)}for(;l.brackets>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));l.output=Y.escapeLast(l.output,"["),oe("brackets")}for(;l.parens>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing",")"));l.output=Y.escapeLast(l.output,"("),oe("parens")}for(;l.braces>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","}"));l.output=Y.escapeLast(l.output,"{"),oe("braces")}if(t.strictSlashes!==!0&&(o.type==="star"||o.type==="bracket")&&C({type:"maybe_slash",value:"",output:`${$}?`}),l.backtrack===!0){l.output="";for(let A of l.tokens)l.output+=A.output!=null?A.output:A.value,A.suffix&&(l.output+=A.suffix)}return l};Vt.fastpaths=(e,r)=>{let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);e=zt[e]||e;let i=Y.isWindows(r),{DOT_LITERAL:a,SLASH_LITERAL:c,ONE_CHAR:p,DOTS_SLASH:m,NO_DOT:h,NO_DOTS:R,NO_DOTS_SLASH:f,STAR:$,START_ANCHOR:_}=ke.globChars(i),y=t.dot?R:h,E=t.dot?f:h,S=t.capture?"":"?:",T={negated:!1,prefix:""},L=t.bash===!0?".*?":$;t.capture&&(L=`(${L})`);let z=g=>g.noglobstar===!0?L:`(${S}(?:(?!${_}${g.dot?m:a}).)*?)`,I=g=>{switch(g){case"*":return`${y}${p}${L}`;case".*":return`${a}${p}${L}`;case"*.*":return`${y}${L}${a}${p}${L}`;case"*/*":return`${y}${L}${c}${p}${E}${L}`;case"**":return y+z(t);case"**/*":return`(?:${y}${z(t)}${c})?${E}${p}${L}`;case"**/*.*":return`(?:${y}${z(t)}${c})?${E}${L}${a}${p}${L}`;case"**/.*":return`(?:${y}${z(t)}${c})?${a}${p}${L}`;default:{let v=/^(.*?)\.(\w+)$/.exec(g);if(!v)return;let k=I(v[1]);return k?k+a+v[2]:void 0}}},re=Y.removePrefix(e,T),K=I(re);return K&&t.strictSlashes!==!0&&(K+=`${c}?`),K};Jt.exports=Vt});var rr=q((ls,tr)=>{"use strict";var Pn=W("path"),Mn=Yt(),Ze=er(),Ye=Re(),Dn=me(),Un=e=>e&&typeof e=="object"&&!Array.isArray(e),D=(e,r,t=!1)=>{if(Array.isArray(e)){let h=e.map(f=>D(f,r,t));return f=>{for(let $ of h){let _=$(f);if(_)return _}return!1}}let n=Un(e)&&e.tokens&&e.input;if(e===""||typeof e!="string"&&!n)throw new TypeError("Expected pattern to be a non-empty string");let s=r||{},i=Ye.isWindows(r),a=n?D.compileRe(e,r):D.makeRe(e,r,!1,!0),c=a.state;delete a.state;let p=()=>!1;if(s.ignore){let h={...r,ignore:null,onMatch:null,onResult:null};p=D(s.ignore,h,t)}let m=(h,R=!1)=>{let{isMatch:f,match:$,output:_}=D.test(h,a,r,{glob:e,posix:i}),y={glob:e,state:c,regex:a,posix:i,input:h,output:_,match:$,isMatch:f};return typeof s.onResult=="function"&&s.onResult(y),f===!1?(y.isMatch=!1,R?y:!1):p(h)?(typeof s.onIgnore=="function"&&s.onIgnore(y),y.isMatch=!1,R?y:!1):(typeof s.onMatch=="function"&&s.onMatch(y),R?y:!0)};return t&&(m.state=c),m};D.test=(e,r,t,{glob:n,posix:s}={})=>{if(typeof e!="string")throw new TypeError("Expected input to be a string");if(e==="")return{isMatch:!1,output:""};let i=t||{},a=i.format||(s?Ye.toPosixSlashes:null),c=e===n,p=c&&a?a(e):e;return c===!1&&(p=a?a(e):e,c=p===n),(c===!1||i.capture===!0)&&(i.matchBase===!0||i.basename===!0?c=D.matchBase(e,r,t,s):c=r.exec(p)),{isMatch:Boolean(c),match:c,output:p}};D.matchBase=(e,r,t,n=Ye.isWindows(t))=>(r instanceof RegExp?r:D.makeRe(r,t)).test(Pn.basename(e));D.isMatch=(e,r,t)=>D(r,t)(e);D.parse=(e,r)=>Array.isArray(e)?e.map(t=>D.parse(t,r)):Ze(e,{...r,fastpaths:!1});D.scan=(e,r)=>Mn(e,r);D.compileRe=(e,r,t=!1,n=!1)=>{if(t===!0)return e.output;let s=r||{},i=s.contains?"":"^",a=s.contains?"":"$",c=`${i}(?:${e.output})${a}`;e&&e.negated===!0&&(c=`^(?!${c}).*$`);let p=D.toRegex(c,r);return n===!0&&(p.state=e),p};D.makeRe=(e,r={},t=!1,n=!1)=>{if(!e||typeof e!="string")throw new TypeError("Expected a non-empty string");let s={negated:!1,fastpaths:!0};return r.fastpaths!==!1&&(e[0]==="."||e[0]==="*")&&(s.output=Ze.fastpaths(e,r)),s.output||(s=Ze(e,r)),D.compileRe(s,r,t,n)};D.toRegex=(e,r)=>{try{let t=r||{};return new RegExp(e,t.flags||(t.nocase?"i":""))}catch(t){if(r&&r.debug===!0)throw t;return/$^/}};D.constants=Dn;tr.exports=D});var sr=q((fs,nr)=>{"use strict";nr.exports=rr()});var cr=q((ps,ur)=>{"use strict";var ir=W("util"),or=Pt(),ae=sr(),ze=Re(),ar=e=>e===""||e==="./",N=(e,r,t)=>{r=[].concat(r),e=[].concat(e);let n=new Set,s=new Set,i=new Set,a=0,c=h=>{i.add(h.output),t&&t.onResult&&t.onResult(h)};for(let h=0;h!n.has(h));if(t&&m.length===0){if(t.failglob===!0)throw new Error(`No matches found for "${r.join(", ")}"`);if(t.nonull===!0||t.nullglob===!0)return t.unescape?r.map(h=>h.replace(/\\/g,"")):r}return m};N.match=N;N.matcher=(e,r)=>ae(e,r);N.isMatch=(e,r,t)=>ae(r,t)(e);N.any=N.isMatch;N.not=(e,r,t={})=>{r=[].concat(r).map(String);let n=new Set,s=[],a=N(e,r,{...t,onResult:c=>{t.onResult&&t.onResult(c),s.push(c.output)}});for(let c of s)a.includes(c)||n.add(c);return[...n]};N.contains=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);if(Array.isArray(r))return r.some(n=>N.contains(e,n,t));if(typeof r=="string"){if(ar(e)||ar(r))return!1;if(e.includes(r)||e.startsWith("./")&&e.slice(2).includes(r))return!0}return N.isMatch(e,r,{...t,contains:!0})};N.matchKeys=(e,r,t)=>{if(!ze.isObject(e))throw new TypeError("Expected the first argument to be an object");let n=N(Object.keys(e),r,t),s={};for(let i of n)s[i]=e[i];return s};N.some=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(n.some(a=>i(a)))return!0}return!1};N.every=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(!n.every(a=>i(a)))return!1}return!0};N.all=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);return[].concat(r).every(n=>ae(n,t)(e))};N.capture=(e,r,t)=>{let n=ze.isWindows(t),i=ae.makeRe(String(e),{...t,capture:!0}).exec(n?ze.toPosixSlashes(r):r);if(i)return i.slice(1).map(a=>a===void 0?"":a)};N.makeRe=(...e)=>ae.makeRe(...e);N.scan=(...e)=>ae.scan(...e);N.parse=(e,r)=>{let t=[];for(let n of[].concat(e||[]))for(let s of or(String(n),r))t.push(ae.parse(s,r));return t};N.braces=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return r&&r.nobrace===!0||!/\{.*\}/.test(e)?[e]:or(e,r)};N.braceExpand=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return N.braces(e,{...r,expand:!0})};ur.exports=N});var fr=q((hs,lr)=>{"use strict";lr.exports=(e,...r)=>new Promise(t=>{t(e(...r))})});var hr=q((ds,Ve)=>{"use strict";var Gn=fr(),pr=e=>{if(e<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let r=[],t=0,n=()=>{t--,r.length>0&&r.shift()()},s=(c,p,...m)=>{t++;let h=Gn(c,...m);p(h),h.then(n,n)},i=(c,p,...m)=>{tnew Promise(m=>i(c,m,...p));return Object.defineProperties(a,{activeCount:{get:()=>t},pendingCount:{get:()=>r.length}}),a};Ve.exports=pr;Ve.exports.default=pr});var jn={};Cr(jn,{default:()=>Wn});var Se=W("@yarnpkg/cli"),ne=W("@yarnpkg/core"),et=W("@yarnpkg/core"),ue=W("clipanion"),ce=class extends Se.BaseCommand{constructor(){super(...arguments);this.json=ue.Option.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ue.Option.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ue.Option.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ue.Option.Rest()}async execute(){let t=await ne.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ne.Project.find(t,this.context.cwd),i=await ne.Cache.find(t);await n.restoreInstallState({restoreResolutions:!1});let a;if(this.all)a=new Set(n.workspaces);else if(this.workspaces.length===0){if(!s)throw new Se.WorkspaceRequiredError(n.cwd,this.context.cwd);a=new Set([s])}else a=new Set(this.workspaces.map(p=>n.getWorkspaceByIdent(et.structUtils.parseIdent(p))));for(let p of a)for(let m of this.production?["dependencies"]:ne.Manifest.hardDependencies)for(let h of p.manifest.getForScope(m).values()){let R=n.tryWorkspaceByDescriptor(h);R!==null&&a.add(R)}for(let p of n.workspaces)a.has(p)?this.production&&p.manifest.devDependencies.clear():(p.manifest.installConfig=p.manifest.installConfig||{},p.manifest.installConfig.selfReferences=!1,p.manifest.dependencies.clear(),p.manifest.devDependencies.clear(),p.manifest.peerDependencies.clear(),p.manifest.scripts.clear());return(await ne.StreamReport.start({configuration:t,json:this.json,stdout:this.context.stdout,includeLogs:!0},async p=>{await n.install({cache:i,report:p,persistProject:!1})})).exitCode()}};ce.paths=[["workspaces","focus"]],ce.usage=ue.Command.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});var Ne=W("@yarnpkg/cli"),ge=W("@yarnpkg/core"),_e=W("@yarnpkg/core"),F=W("@yarnpkg/core"),gr=W("@yarnpkg/plugin-git"),U=W("clipanion"),Oe=Be(cr()),Ar=Be(hr()),te=Be(W("typanion")),pe=class extends Ne.BaseCommand{constructor(){super(...arguments);this.recursive=U.Option.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.from=U.Option.Array("--from",[],{description:"An array of glob pattern idents from which to base any recursion"});this.all=U.Option.Boolean("-A,--all",!1,{description:"Run the command on all workspaces of a project"});this.verbose=U.Option.Boolean("-v,--verbose",!1,{description:"Prefix each output line with the name of the originating workspace"});this.parallel=U.Option.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=U.Option.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=U.Option.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:te.isOneOf([te.isEnum(["unlimited"]),te.applyCascade(te.isNumber(),[te.isInteger(),te.isAtLeast(1)])])});this.topological=U.Option.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=U.Option.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=U.Option.Array("--include",[],{description:"An array of glob pattern idents; only matching workspaces will be traversed"});this.exclude=U.Option.Array("--exclude",[],{description:"An array of glob pattern idents; matching workspaces won't be traversed"});this.publicOnly=U.Option.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=U.Option.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.commandName=U.Option.String();this.args=U.Option.Proxy()}async execute(){let t=await ge.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ge.Project.find(t,this.context.cwd);if(!this.all&&!s)throw new Ne.WorkspaceRequiredError(n.cwd,this.context.cwd);await n.restoreInstallState();let i=this.cli.process([this.commandName,...this.args]),a=i.path.length===1&&i.path[0]==="run"&&typeof i.scriptName<"u"?i.scriptName:null;if(i.path.length===0)throw new U.UsageError("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let c=this.all?n.topLevelWorkspace:s,p=this.since?Array.from(await gr.gitUtils.fetchChangedWorkspaces({ref:this.since,project:n})):[c,...this.from.length>0?c.getRecursiveWorkspaceChildren():[]],m=g=>Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.from),h=this.from.length>0?p.filter(m):p,R=new Set([...h,...h.map(g=>[...this.recursive?this.since?g.getRecursiveWorkspaceDependents():g.getRecursiveWorkspaceDependencies():g.getRecursiveWorkspaceChildren()]).flat()]),f=[],$=!1;if(a!=null&&a.includes(":")){for(let g of n.workspaces)if(g.manifest.scripts.has(a)&&($=!$,$===!1))break}for(let g of R)a&&!g.manifest.scripts.has(a)&&!$&&!(await ge.scriptUtils.getWorkspaceAccessibleBinaries(g)).has(a)||a===process.env.npm_lifecycle_event&&g.cwd===s.cwd||this.include.length>0&&!Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.include)||this.exclude.length>0&&Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.exclude)||this.publicOnly&&g.manifest.private===!0||f.push(g);let _=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(F.nodeUtils.availableParallelism()/2):1,y=_===1?!1:this.parallel,E=y?this.interlaced:!0,S=(0,Ar.default)(_),T=new Map,L=new Set,z=0,I=null,re=!1,K=await _e.StreamReport.start({configuration:t,stdout:this.context.stdout,includePrefix:!1},async g=>{let v=async(k,{commandIndex:l})=>{if(re)return-1;!y&&this.verbose&&l>1&&g.reportSeparator();let H=qn(k,{configuration:t,verbose:this.verbose,commandIndex:l}),[w,B]=dr(g,{prefix:H,interlaced:E}),[o,u]=dr(g,{prefix:H,interlaced:E});try{this.verbose&&g.reportInfo(null,`${H} Process started`);let P=Date.now(),b=await this.cli.run([this.commandName,...this.args],{cwd:k.cwd,stdout:w,stderr:o})||0;w.end(),o.end(),await B,await u;let V=Date.now();if(this.verbose){let J=t.get("enableTimers")?`, completed in ${F.formatUtils.pretty(t,V-P,F.formatUtils.Type.DURATION)}`:"";g.reportInfo(null,`${H} Process exited (exit code ${b})${J}`)}return b===130&&(re=!0,I=b),b}catch(P){throw w.end(),o.end(),await B,await u,P}};for(let k of f)T.set(k.anchoredLocator.locatorHash,k);for(;T.size>0&&!g.hasErrors();){let k=[];for(let[w,B]of T){if(L.has(B.anchoredDescriptor.descriptorHash))continue;let o=!0;if(this.topological||this.topologicalDev){let u=this.topologicalDev?new Map([...B.manifest.dependencies,...B.manifest.devDependencies]):B.manifest.dependencies;for(let P of u.values()){let b=n.tryWorkspaceByDescriptor(P);if(o=b===null||!T.has(b.anchoredLocator.locatorHash),!o)break}}if(!!o&&(L.add(B.anchoredDescriptor.descriptorHash),k.push(S(async()=>{let u=await v(B,{commandIndex:++z});return T.delete(w),L.delete(B.anchoredDescriptor.descriptorHash),u})),!y))break}if(k.length===0){let w=Array.from(T.values()).map(B=>F.structUtils.prettyLocator(t,B.anchoredLocator)).join(", ");g.reportError(_e.MessageName.CYCLIC_DEPENDENCIES,`Dependency cycle detected (${w})`);return}let H=(await Promise.all(k)).find(w=>w!==0);I===null&&(I=typeof H<"u"?1:I),(this.topological||this.topologicalDev)&&typeof H<"u"&&g.reportError(_e.MessageName.UNNAMED,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return I!==null?I:K.exitCode()}};pe.paths=[["workspaces","foreach"]],pe.usage=U.Command.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project. By default yarn runs the command only on current and all its descendant workspaces.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n Adding the `-v,--verbose` flag will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish current and all descendant packages","yarn workspaces foreach npm publish --tolerate-republish"],["Run build script on current and all descendant packages","yarn workspaces foreach run build"],["Run build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -pt run build"],["Run build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -ptR --from '{workspace-a,workspace-b}' run build"]]});function dr(e,{prefix:r,interlaced:t}){let n=e.createStreamReporter(r),s=new F.miscUtils.DefaultStream;s.pipe(n,{end:!1}),s.on("finish",()=>{n.end()});let i=new Promise(c=>{n.on("finish",()=>{c(s.active)})});if(t)return[s,i];let a=new F.miscUtils.BufferStream;return a.pipe(s,{end:!1}),a.on("finish",()=>{s.end()}),[a,i]}function qn(e,{configuration:r,commandIndex:t,verbose:n}){if(!n)return null;let i=`[${F.structUtils.stringifyIdent(e.locator)}]:`,a=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],c=a[t%a.length];return F.formatUtils.pretty(r,i,c)}var Kn={commands:[ce,pe]},Wn=Kn;return wr(jn);})(); 8 | /*! 9 | * fill-range 10 | * 11 | * Copyright (c) 2014-present, Jon Schlinkert. 12 | * Licensed under the MIT License. 13 | */ 14 | /*! 15 | * is-number 16 | * 17 | * Copyright (c) 2014-present, Jon Schlinkert. 18 | * Released under the MIT License. 19 | */ 20 | /*! 21 | * to-regex-range 22 | * 23 | * Copyright (c) 2015-present, Jon Schlinkert. 24 | * Released under the MIT License. 25 | */ 26 | return plugin; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | nmHoistingLimits: workspaces 3 | 4 | plugins: 5 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 6 | spec: "@yarnpkg/plugin-interactive-tools" 7 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 8 | spec: "@yarnpkg/plugin-workspace-tools" 9 | 10 | yarnPath: .yarn/releases/yarn-3.6.1.cjs 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [INSERT CONTACT METHOD]. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome, no matter how large or small! 4 | 5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md). 6 | 7 | ## Development workflow 8 | 9 | This project is a monorepo managed using [Yarn workspaces](https://yarnpkg.com/features/workspaces). It contains the following packages: 10 | 11 | - The library package in the root directory. 12 | - An example app in the `example/` directory. 13 | 14 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: 15 | 16 | ```sh 17 | yarn 18 | ``` 19 | 20 | > Since the project relies on Yarn workspaces, you cannot use [`npm`](https://github.com/npm/cli) for development. 21 | 22 | The [example app](/example/) demonstrates usage of the library. You need to run it to test any changes you make. 23 | 24 | It is configured to use the local version of the library, so any changes you make to the library's source code will be reflected in the example app. Changes to the library's JavaScript code will be reflected in the example app without a rebuild, but native code changes will require a rebuild of the example app. 25 | 26 | If you want to use Android Studio or XCode to edit the native code, you can open the `example/android` or `example/ios` directories respectively in those editors. To edit the Objective-C or Swift files, open `example/ios/ReactNativeRapierExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > @callstack/react-native-rapier`. 27 | 28 | To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `callstack-react-native-rapier` under `Android`. 29 | 30 | You can use various commands from the root directory to work with the project. 31 | 32 | To start the packager: 33 | 34 | ```sh 35 | yarn example start 36 | ``` 37 | 38 | To run the example app on Android: 39 | 40 | ```sh 41 | yarn example android 42 | ``` 43 | 44 | To run the example app on iOS: 45 | 46 | ```sh 47 | yarn example ios 48 | ``` 49 | 50 | By default, the example is configured to build with the old architecture. To run the example with the new architecture, you can do the following: 51 | 52 | 1. For Android, run: 53 | 54 | ```sh 55 | ORG_GRADLE_PROJECT_newArchEnabled=true yarn example android 56 | ``` 57 | 58 | 2. For iOS, run: 59 | 60 | ```sh 61 | cd example/ios 62 | RCT_NEW_ARCH_ENABLED=1 pod install 63 | cd - 64 | yarn example ios 65 | ``` 66 | 67 | If you are building for a different architecture than your previous build, make sure to remove the build folders first. You can run the following command to cleanup all build folders: 68 | 69 | ```sh 70 | yarn clean 71 | ``` 72 | 73 | To confirm that the app is running with the new architecture, you can check the Metro logs for a message like this: 74 | 75 | ```sh 76 | Running "ReactNativeRapierExample" with {"fabric":true,"initialProps":{"concurrentRoot":true},"rootTag":1} 77 | ``` 78 | 79 | Note the `"fabric":true` and `"concurrentRoot":true` properties. 80 | 81 | Make sure your code passes TypeScript and ESLint. Run the following to verify: 82 | 83 | ```sh 84 | yarn typecheck 85 | yarn lint 86 | ``` 87 | 88 | To fix formatting errors, run the following: 89 | 90 | ```sh 91 | yarn lint --fix 92 | ``` 93 | 94 | Remember to add tests for your change if possible. Run the unit tests by: 95 | 96 | ```sh 97 | yarn test 98 | ``` 99 | 100 | ### Commit message convention 101 | 102 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: 103 | 104 | - `fix`: bug fixes, e.g. fix crash due to deprecated method. 105 | - `feat`: new features, e.g. add new method to the module. 106 | - `refactor`: code refactor, e.g. migrate from class components to hooks. 107 | - `docs`: changes into documentation, e.g. add usage example for the module.. 108 | - `test`: adding or updating tests, e.g. add integration tests using detox. 109 | - `chore`: tooling changes, e.g. change CI config. 110 | 111 | Our pre-commit hooks verify that your commit message matches this format when committing. 112 | 113 | ### Linting and tests 114 | 115 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/) 116 | 117 | 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. 118 | 119 | Our pre-commit hooks verify that the linter and tests pass when committing. 120 | 121 | ### Publishing to npm 122 | 123 | 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. 124 | 125 | To publish new versions, run the following: 126 | 127 | ```sh 128 | yarn release 129 | ``` 130 | 131 | ### Scripts 132 | 133 | The `package.json` file contains various scripts for common tasks: 134 | 135 | - `yarn`: setup project by installing dependencies. 136 | - `yarn typecheck`: type-check files with TypeScript. 137 | - `yarn lint`: lint files with ESLint. 138 | - `yarn test`: run unit tests with Jest. 139 | - `yarn example start`: start the Metro server for the example app. 140 | - `yarn example android`: run the example app on Android. 141 | - `yarn example ios`: run the example app on iOS. 142 | 143 | ### Sending a pull request 144 | 145 | > **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). 146 | 147 | When you're sending a pull request: 148 | 149 | - Prefer small pull requests focused on one change. 150 | - Verify that linters and tests are passing. 151 | - Review the documentation to make sure it looks good. 152 | - Follow the pull request template when opening a pull request. 153 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue. 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Oskar Kwasniewski 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @callstack/react-native-rapier 2 | 3 | Fast 2D and 3D physics engine for React Native. 4 | 5 | Unoffical bindings for [rapier.rs](https://rapier.rs/). 6 | 7 | ## Installation 8 | 9 | ```sh 10 | npm install @callstack/react-native-rapier 11 | ``` 12 | 13 | ## Usage 14 | 15 | Refer to the [rapier.rs](https://rapier.rs/) documentation for usage. 16 | 17 | 18 | ## Contributing 19 | 20 | See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. 21 | 22 | ## License 23 | 24 | MIT 25 | 26 | --- 27 | 28 | Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 29 | -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | project(ReactNativeRapier) 3 | 4 | set (CMAKE_VERBOSE_MAKEFILE ON) 5 | set (CMAKE_CXX_STANDARD 14) 6 | 7 | add_library(callstack-react-native-rapier SHARED 8 | ../cpp/callstack-react-native-rapier.cpp 9 | cpp-adapter.cpp 10 | ) 11 | 12 | # Specifies a path to native header files. 13 | include_directories( 14 | ../cpp 15 | ) 16 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | // Buildscript is evaluated before everything else so we can't use getExtOrDefault 3 | def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["ReactNativeRapier_kotlinVersion"] 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath "com.android.tools.build:gradle:7.2.1" 12 | // noinspection DifferentKotlinGradleVersion 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | def reactNativeArchitectures() { 18 | def value = rootProject.getProperties().get("reactNativeArchitectures") 19 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 20 | } 21 | 22 | def isNewArchitectureEnabled() { 23 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 24 | } 25 | 26 | apply plugin: "com.android.library" 27 | apply plugin: "kotlin-android" 28 | 29 | if (isNewArchitectureEnabled()) { 30 | apply plugin: "com.facebook.react" 31 | } 32 | 33 | def getExtOrDefault(name) { 34 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["ReactNativeRapier_" + name] 35 | } 36 | 37 | def getExtOrIntegerDefault(name) { 38 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeRapier_" + name]).toInteger() 39 | } 40 | 41 | def supportsNamespace() { 42 | def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.') 43 | def major = parsed[0].toInteger() 44 | def minor = parsed[1].toInteger() 45 | 46 | // Namespace support was added in 7.3.0 47 | return (major == 7 && minor >= 3) || major >= 8 48 | } 49 | 50 | android { 51 | if (supportsNamespace()) { 52 | namespace "com.callstack.reactnativerapier" 53 | 54 | sourceSets { 55 | main { 56 | manifest.srcFile "src/main/AndroidManifestNew.xml" 57 | } 58 | } 59 | } 60 | 61 | ndkVersion getExtOrDefault("ndkVersion") 62 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 63 | 64 | defaultConfig { 65 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 66 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 67 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 68 | 69 | externalNativeBuild { 70 | cmake { 71 | cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all" 72 | abiFilters (*reactNativeArchitectures()) 73 | } 74 | } 75 | } 76 | 77 | externalNativeBuild { 78 | cmake { 79 | path "CMakeLists.txt" 80 | } 81 | } 82 | 83 | buildFeatures { 84 | buildConfig true 85 | } 86 | 87 | buildTypes { 88 | release { 89 | minifyEnabled false 90 | } 91 | } 92 | 93 | lintOptions { 94 | disable "GradleCompatible" 95 | } 96 | 97 | compileOptions { 98 | sourceCompatibility JavaVersion.VERSION_1_8 99 | targetCompatibility JavaVersion.VERSION_1_8 100 | } 101 | 102 | sourceSets { 103 | main { 104 | if (isNewArchitectureEnabled()) { 105 | java.srcDirs += [ 106 | "src/newarch", 107 | // Codegen specs 108 | "generated/java", 109 | "generated/jni" 110 | ] 111 | } else { 112 | java.srcDirs += ["src/oldarch"] 113 | } 114 | } 115 | } 116 | } 117 | 118 | repositories { 119 | mavenCentral() 120 | google() 121 | } 122 | 123 | def kotlin_version = getExtOrDefault("kotlinVersion") 124 | 125 | dependencies { 126 | // For < 0.71, this will be from the local maven repo 127 | // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin 128 | //noinspection GradleDynamicVersion 129 | implementation "com.facebook.react:react-native:+" 130 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 131 | } 132 | 133 | if (isNewArchitectureEnabled()) { 134 | react { 135 | jsRootDir = file("../src/") 136 | libraryName = "ReactNativeRapier" 137 | codegenJavaPackageName = "com.callstack.reactnativerapier" 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /android/cpp-adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "callstack-react-native-rapier.h" 3 | 4 | extern "C" 5 | JNIEXPORT jdouble JNICALL 6 | Java_com_callstack_reactnativerapier_ReactNativeRapierModule_nativeMultiply(JNIEnv *env, jclass type, jdouble a, jdouble b) { 7 | return callstack_reactnativerapier::multiply(a, b); 8 | } 9 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | ReactNativeRapier_kotlinVersion=1.7.0 2 | ReactNativeRapier_minSdkVersion=21 3 | ReactNativeRapier_targetSdkVersion=31 4 | ReactNativeRapier_compileSdkVersion=31 5 | ReactNativeRapier_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifestNew.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/src/main/java/com/callstack/reactnativerapier/ReactNativeRapierModule.kt: -------------------------------------------------------------------------------- 1 | package com.callstack.reactnativerapier 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext 4 | import com.facebook.react.bridge.ReactMethod 5 | import com.facebook.react.bridge.Promise 6 | 7 | class ReactNativeRapierModule internal constructor(context: ReactApplicationContext) : 8 | ReactNativeRapierSpec(context) { 9 | 10 | override fun getName(): String { 11 | return NAME 12 | } 13 | 14 | // Example method 15 | // See https://reactnative.dev/docs/native-modules-android 16 | @ReactMethod 17 | override fun multiply(a: Double, b: Double, promise: Promise) { 18 | promise.resolve(a * b) 19 | } 20 | 21 | companion object { 22 | const val NAME = "ReactNativeRapier" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/src/main/java/com/callstack/reactnativerapier/ReactNativeRapierPackage.kt: -------------------------------------------------------------------------------- 1 | package com.callstack.reactnativerapier 2 | 3 | import com.facebook.react.TurboReactPackage 4 | import com.facebook.react.bridge.ReactApplicationContext 5 | import com.facebook.react.bridge.NativeModule 6 | import com.facebook.react.module.model.ReactModuleInfoProvider 7 | import com.facebook.react.module.model.ReactModuleInfo 8 | import java.util.HashMap 9 | 10 | class ReactNativeRapierPackage : TurboReactPackage() { 11 | override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { 12 | return if (name == ReactNativeRapierModule.NAME) { 13 | ReactNativeRapierModule(reactContext) 14 | } else { 15 | null 16 | } 17 | } 18 | 19 | override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { 20 | return ReactModuleInfoProvider { 21 | val moduleInfos: MutableMap = HashMap() 22 | val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 23 | moduleInfos[ReactNativeRapierModule.NAME] = ReactModuleInfo( 24 | ReactNativeRapierModule.NAME, 25 | ReactNativeRapierModule.NAME, 26 | false, // canOverrideExistingModule 27 | false, // needsEagerInit 28 | true, // hasConstants 29 | false, // isCxxModule 30 | isTurboModule // isTurboModule 31 | ) 32 | moduleInfos 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /android/src/newarch/ReactNativeRapierSpec.kt: -------------------------------------------------------------------------------- 1 | package com.callstack.reactnativerapier 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext 4 | 5 | abstract class ReactNativeRapierSpec internal constructor(context: ReactApplicationContext) : 6 | NativeReactNativeRapierSpec(context) { 7 | } 8 | -------------------------------------------------------------------------------- /android/src/oldarch/ReactNativeRapierSpec.kt: -------------------------------------------------------------------------------- 1 | package com.callstack.reactnativerapier 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext 4 | import com.facebook.react.bridge.ReactContextBaseJavaModule 5 | import com.facebook.react.bridge.Promise 6 | 7 | abstract class ReactNativeRapierSpec internal constructor(context: ReactApplicationContext) : 8 | ReactContextBaseJavaModule(context) { 9 | 10 | abstract fun multiply(a: Double, b: Double, promise: Promise) 11 | } 12 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['module:react-native-builder-bob/babel-preset', { modules: 'commonjs' }], 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /cpp/gen/jsi-exports-bridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS FILE WAS GENERATED BY `react-native-wasm` 3 | // 4 | // DO NOT EDIT THIS FILE. ANY CHANGES WILL BE LOST. 5 | // 6 | 7 | #pragma once 8 | #include "jsi-imports-bridge.h" 9 | 10 | namespace facebook::react { 11 | 12 | jsi::Object createRapier__wasm3d__bgExports(jsi::Runtime &rt, jsi::Object importObject); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /cpp/gen/jsi-imports-bridge.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // THIS FILE WAS GENERATED BY `react-native-wasm` 3 | // 4 | // DO NOT EDIT THIS FILE. ANY CHANGES WILL BE LOST. 5 | // 6 | 7 | #include "jsi-imports-bridge.h" 8 | 9 | using namespace facebook; 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | 16 | /* import: 'wbg' '__wbindgen_number_new' */ 17 | u32 w2c_wbg_0x5F_wbindgen_number_new(w2c_wbg* ctx, f64 arg0) { 18 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_number_new"); 19 | 20 | return 21 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 22 | }).asNumber(); 23 | } 24 | 25 | /* import: 'wbg' '__wbindgen_boolean_get' */ 26 | u32 w2c_wbg_0x5F_wbindgen_boolean_get(w2c_wbg* ctx, u32 arg0) { 27 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_boolean_get"); 28 | 29 | return 30 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 31 | }).asNumber(); 32 | } 33 | 34 | /* import: 'wbg' '__wbindgen_object_drop_ref' */ 35 | void w2c_wbg_0x5F_wbindgen_object_drop_ref(w2c_wbg* ctx, u32 arg0) { 36 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_object_drop_ref"); 37 | 38 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 39 | }); 40 | } 41 | 42 | /* import: 'wbg' '__wbindgen_number_get' */ 43 | void w2c_wbg_0x5F_wbindgen_number_get(w2c_wbg* ctx, u32 arg0, u32 arg1) { 44 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_number_get"); 45 | 46 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 } 47 | }); 48 | } 49 | 50 | /* import: 'wbg' '__wbindgen_is_function' */ 51 | u32 w2c_wbg_0x5F_wbindgen_is_function(w2c_wbg* ctx, u32 arg0) { 52 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_is_function"); 53 | 54 | return 55 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 56 | }).asNumber(); 57 | } 58 | 59 | /* import: 'wbg' '__wbg_rawraycolliderintersection_new' */ 60 | u32 w2c_wbg_0x5F_wbg_rawraycolliderintersection_new(w2c_wbg* ctx, u32 arg0) { 61 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_rawraycolliderintersection_new"); 62 | 63 | return 64 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 65 | }).asNumber(); 66 | } 67 | 68 | /* import: 'wbg' '__wbg_rawcontactforceevent_new' */ 69 | u32 w2c_wbg_0x5F_wbg_rawcontactforceevent_new(w2c_wbg* ctx, u32 arg0) { 70 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_rawcontactforceevent_new"); 71 | 72 | return 73 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 74 | }).asNumber(); 75 | } 76 | 77 | /* import: 'wbg' '__wbg_call_b3ca7c6051f9bec1' */ 78 | u32 w2c_wbg_0x5F_wbg_call_b3ca7c6051f9bec1(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2) { 79 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_call_b3ca7c6051f9bec1"); 80 | 81 | return 82 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 } 83 | }).asNumber(); 84 | } 85 | 86 | /* import: 'wbg' '__wbg_call_8e7cb608789c2528' */ 87 | u32 w2c_wbg_0x5F_wbg_call_8e7cb608789c2528(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2, u32 arg3) { 88 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_call_8e7cb608789c2528"); 89 | 90 | return 91 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 },jsi::Value { (double)arg3 } 92 | }).asNumber(); 93 | } 94 | 95 | /* import: 'wbg' '__wbg_call_938992c832f74314' */ 96 | u32 w2c_wbg_0x5F_wbg_call_938992c832f74314(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { 97 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_call_938992c832f74314"); 98 | 99 | return 100 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 },jsi::Value { (double)arg3 },jsi::Value { (double)arg4 } 101 | }).asNumber(); 102 | } 103 | 104 | /* import: 'wbg' '__wbg_bind_4d857b598695205e' */ 105 | u32 w2c_wbg_0x5F_wbg_bind_4d857b598695205e(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2, u32 arg3) { 106 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_bind_4d857b598695205e"); 107 | 108 | return 109 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 },jsi::Value { (double)arg3 } 110 | }).asNumber(); 111 | } 112 | 113 | /* import: 'wbg' '__wbg_buffer_12d079cc21e14bdb' */ 114 | u32 w2c_wbg_0x5F_wbg_buffer_12d079cc21e14bdb(w2c_wbg* ctx, u32 arg0) { 115 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_buffer_12d079cc21e14bdb"); 116 | 117 | return 118 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 119 | }).asNumber(); 120 | } 121 | 122 | /* import: 'wbg' '__wbg_newwithbyteoffsetandlength_aa4a17c33a06e5cb' */ 123 | u32 w2c_wbg_0x5F_wbg_newwithbyteoffsetandlength_aa4a17c33a06e5cb(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2) { 124 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_newwithbyteoffsetandlength_aa4a17c33a06e5cb"); 125 | 126 | return 127 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 } 128 | }).asNumber(); 129 | } 130 | 131 | /* import: 'wbg' '__wbg_new_63b92bc8671ed464' */ 132 | u32 w2c_wbg_0x5F_wbg_new_63b92bc8671ed464(w2c_wbg* ctx, u32 arg0) { 133 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_new_63b92bc8671ed464"); 134 | 135 | return 136 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 137 | }).asNumber(); 138 | } 139 | 140 | /* import: 'wbg' '__wbg_set_a47bac70306a19a7' */ 141 | void w2c_wbg_0x5F_wbg_set_a47bac70306a19a7(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2) { 142 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_set_a47bac70306a19a7"); 143 | 144 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 } 145 | }); 146 | } 147 | 148 | /* import: 'wbg' '__wbg_length_c20a40f15020d68a' */ 149 | u32 w2c_wbg_0x5F_wbg_length_c20a40f15020d68a(w2c_wbg* ctx, u32 arg0) { 150 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_length_c20a40f15020d68a"); 151 | 152 | return 153 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 154 | }).asNumber(); 155 | } 156 | 157 | /* import: 'wbg' '__wbg_newwithbyteoffsetandlength_4a659d079a1650e0' */ 158 | u32 w2c_wbg_0x5F_wbg_newwithbyteoffsetandlength_4a659d079a1650e0(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2) { 159 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_newwithbyteoffsetandlength_4a659d079a1650e0"); 160 | 161 | return 162 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 } 163 | }).asNumber(); 164 | } 165 | 166 | /* import: 'wbg' '__wbg_set_bd975934d1b1fddb' */ 167 | void w2c_wbg_0x5F_wbg_set_bd975934d1b1fddb(w2c_wbg* ctx, u32 arg0, u32 arg1, u32 arg2) { 168 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_set_bd975934d1b1fddb"); 169 | 170 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 },jsi::Value { (double)arg2 } 171 | }); 172 | } 173 | 174 | /* import: 'wbg' '__wbg_length_d25bbcbc3367f684' */ 175 | u32 w2c_wbg_0x5F_wbg_length_d25bbcbc3367f684(w2c_wbg* ctx, u32 arg0) { 176 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_length_d25bbcbc3367f684"); 177 | 178 | return 179 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 180 | }).asNumber(); 181 | } 182 | 183 | /* import: 'wbg' '__wbg_newwithlength_1e8b839a06de01c5' */ 184 | u32 w2c_wbg_0x5F_wbg_newwithlength_1e8b839a06de01c5(w2c_wbg* ctx, u32 arg0) { 185 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbg_newwithlength_1e8b839a06de01c5"); 186 | 187 | return 188 | fn.call(ctx->rt, {jsi::Value { (double)arg0 } 189 | }).asNumber(); 190 | } 191 | 192 | /* import: 'wbg' '__wbindgen_throw' */ 193 | void w2c_wbg_0x5F_wbindgen_throw(w2c_wbg* ctx, u32 arg0, u32 arg1) { 194 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_throw"); 195 | 196 | fn.call(ctx->rt, {jsi::Value { (double)arg0 },jsi::Value { (double)arg1 } 197 | }); 198 | } 199 | 200 | /* import: 'wbg' '__wbindgen_memory' */ 201 | u32 w2c_wbg_0x5F_wbindgen_memory(w2c_wbg* ctx) { 202 | auto fn = ctx->importObj.getPropertyAsFunction(ctx->rt, "__wbindgen_memory"); 203 | 204 | return 205 | fn.call(ctx->rt, { 206 | }).asNumber(); 207 | } 208 | 209 | 210 | #ifdef __cplusplus 211 | } 212 | #endif 213 | 214 | -------------------------------------------------------------------------------- /cpp/gen/jsi-imports-bridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS FILE WAS GENERATED BY `react-native-wasm` 3 | // 4 | // DO NOT EDIT THIS FILE. ANY CHANGES WILL BE LOST. 5 | // 6 | 7 | #pragma once 8 | #include 9 | #include "rapier_wasm3d_bg.h" 10 | 11 | typedef int i32; 12 | typedef long i64; 13 | typedef unsigned int u32; 14 | typedef unsigned long long u64; 15 | typedef float f32; 16 | typedef double f64; 17 | 18 | 19 | struct w2c_wbg { 20 | w2c_rapier__wasm3d__bg* root; 21 | facebook::jsi::Runtime& rt; 22 | facebook::jsi::Object importObj; 23 | }; 24 | 25 | 26 | namespace facebook::react { 27 | 28 | class Rapier__wasm3d__bgModuleContext: public jsi::NativeState { 29 | public: 30 | Rapier__wasm3d__bgModuleContext(jsi::Runtime& rt, jsi::Object&& importObject) 31 | : importObject(std::move(importObject)) 32 | , wbgCtx{&rootCtx, rt, this->importObject.getPropertyAsObject(rt, "wbg")} 33 | 34 | {} 35 | 36 | jsi::Object importObject; 37 | w2c_rapier__wasm3d__bg rootCtx; 38 | w2c_wbg wbgCtx; 39 | 40 | }; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cpp/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef macros_h 2 | #define macros_h 3 | 4 | #define HOSTFN(name, argCount) \ 5 | jsi::Function::createFromHostFunction( \ 6 | rt, \ 7 | jsi::PropNameID::forAscii(rt, name), \ 8 | argCount, \ 9 | [=](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value 10 | 11 | #endif /* macros_h */ 12 | -------------------------------------------------------------------------------- /cpp/react-native-rapier.cpp: -------------------------------------------------------------------------------- 1 | #include "react-native-rapier.h" 2 | #include "macros.h" 3 | #include "wasm-rt.h" 4 | #include "jsi-exports-bridge.h" 5 | 6 | namespace facebook::react { 7 | 8 | std::shared_ptr tryGetRapierContext(jsi::Runtime& rt, const jsi::Object& rapierObject) { 9 | if (!rapierObject.hasNativeState(rt)) { 10 | return nullptr; 11 | } 12 | 13 | auto context = std::dynamic_pointer_cast(rapierObject.getNativeState(rt)); 14 | return context; 15 | } 16 | 17 | ReactNativeRapier::ReactNativeRapier(std::shared_ptr jsInvoker) 18 | : NativeReactNativeRapierCxxSpecJSI(jsInvoker), _callInvoker(jsInvoker) {} 19 | 20 | jsi::Object ReactNativeRapier::create(jsi::Runtime &rt, jsi::Object importObject) { 21 | return createRapier__wasm3d__bgExports(rt, std::move(importObject)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /cpp/react-native-rapier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jsi-imports-bridge.h" 4 | #include 5 | #include 6 | 7 | namespace facebook::react { 8 | 9 | using namespace facebook; 10 | 11 | class ReactNativeRapier : public NativeReactNativeRapierCxxSpecJSI { 12 | public: 13 | explicit ReactNativeRapier(std::shared_ptr jsInvoker); 14 | 15 | public: 16 | jsi::Object create(jsi::Runtime &rt, jsi::Object importObject) override; 17 | constexpr static auto kModuleName = "ReactNativeRapier"; 18 | 19 | private: 20 | std::shared_ptr _callInvoker; 21 | }; 22 | 23 | } // namespace facebook::react 24 | -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-exceptions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt.h" 18 | 19 | #include "wasm-rt-exceptions.h" 20 | 21 | #include 22 | 23 | #define MAX_EXCEPTION_SIZE 256 24 | 25 | static WASM_RT_THREAD_LOCAL wasm_rt_tag_t g_active_exception_tag; 26 | static WASM_RT_THREAD_LOCAL uint8_t g_active_exception[MAX_EXCEPTION_SIZE]; 27 | static WASM_RT_THREAD_LOCAL uint32_t g_active_exception_size; 28 | 29 | static WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf* g_unwind_target; 30 | 31 | void wasm_rt_load_exception(const wasm_rt_tag_t tag, 32 | uint32_t size, 33 | const void* values) { 34 | if (size > MAX_EXCEPTION_SIZE) { 35 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 36 | } 37 | 38 | g_active_exception_tag = tag; 39 | g_active_exception_size = size; 40 | 41 | if (size) { 42 | memcpy(g_active_exception, values, size); 43 | } 44 | } 45 | 46 | WASM_RT_NO_RETURN void wasm_rt_throw(void) { 47 | WASM_RT_LONGJMP(*g_unwind_target, WASM_RT_TRAP_UNCAUGHT_EXCEPTION); 48 | } 49 | 50 | WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void) { 51 | return g_unwind_target; 52 | } 53 | 54 | void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target) { 55 | g_unwind_target = target; 56 | } 57 | 58 | wasm_rt_tag_t wasm_rt_exception_tag(void) { 59 | return g_active_exception_tag; 60 | } 61 | 62 | uint32_t wasm_rt_exception_size(void) { 63 | return g_active_exception_size; 64 | } 65 | 66 | void* wasm_rt_exception(void) { 67 | return g_active_exception; 68 | } -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-exceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_EXCEPTIONS_H_ 18 | #define WASM_RT_EXCEPTIONS_H_ 19 | 20 | #include "wasm-rt.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * A tag is represented as an arbitrary pointer. 28 | */ 29 | typedef const void* wasm_rt_tag_t; 30 | 31 | /** 32 | * Set the active exception to given tag, size, and contents. 33 | */ 34 | void wasm_rt_load_exception(const wasm_rt_tag_t tag, 35 | uint32_t size, 36 | const void* values); 37 | 38 | /** 39 | * Throw the active exception. 40 | */ 41 | WASM_RT_NO_RETURN void wasm_rt_throw(void); 42 | 43 | /** 44 | * The type of an unwind target if an exception is thrown and caught. 45 | */ 46 | #define WASM_RT_UNWIND_TARGET wasm_rt_jmp_buf 47 | 48 | /** 49 | * Get the current unwind target if an exception is thrown. 50 | */ 51 | WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void); 52 | 53 | /** 54 | * Set the unwind target if an exception is thrown. 55 | */ 56 | void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target); 57 | 58 | /** 59 | * Tag of the active exception. 60 | */ 61 | wasm_rt_tag_t wasm_rt_exception_tag(void); 62 | 63 | /** 64 | * Size of the active exception. 65 | */ 66 | uint32_t wasm_rt_exception_size(void); 67 | 68 | /** 69 | * Contents of the active exception. 70 | */ 71 | void* wasm_rt_exception(void); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-impl-tableops.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file is used as a template to generate code for table operations for 18 | // funcref or externref. For this, the file must be included after defining 19 | // either WASM_RT_TABLE_OPS_FUNCREF or WASM_RT_TABLE_OPS_EXTERNREF 20 | 21 | #if defined(WASM_RT_TABLE_OPS_FUNCREF) && defined(WASM_RT_TABLE_OPS_EXTERNREF) 22 | #error \ 23 | "Expected only one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF } to be defined" 24 | #elif !defined(WASM_RT_TABLE_OPS_FUNCREF) && \ 25 | !defined(WASM_RT_TABLE_OPS_EXTERNREF) 26 | #error \ 27 | "Expected one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF } to be defined" 28 | #endif 29 | 30 | #ifdef WASM_RT_TABLE_OPS_FUNCREF 31 | #define WASM_RT_TABLE_TYPE wasm_rt_funcref_table_t 32 | #define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_funcref_t 33 | #define WASM_RT_TABLE_APINAME(name) name##_funcref_table 34 | #else 35 | #define WASM_RT_TABLE_TYPE wasm_rt_externref_table_t 36 | #define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_externref_t 37 | #define WASM_RT_TABLE_APINAME(name) name##_externref_table 38 | #endif 39 | 40 | void WASM_RT_TABLE_APINAME(wasm_rt_allocate)(WASM_RT_TABLE_TYPE* table, 41 | uint32_t elements, 42 | uint32_t max_elements) { 43 | table->size = elements; 44 | table->max_size = max_elements; 45 | table->data = calloc(table->size, sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); 46 | } 47 | 48 | void WASM_RT_TABLE_APINAME(wasm_rt_free)(WASM_RT_TABLE_TYPE* table) { 49 | free(table->data); 50 | } 51 | 52 | uint32_t WASM_RT_TABLE_APINAME(wasm_rt_grow)(WASM_RT_TABLE_TYPE* table, 53 | uint32_t delta, 54 | WASM_RT_TABLE_ELEMENT_TYPE init) { 55 | uint32_t old_elems = table->size; 56 | uint64_t new_elems = (uint64_t)table->size + delta; 57 | if (new_elems == 0) { 58 | return 0; 59 | } 60 | if ((new_elems < old_elems) || (new_elems > table->max_size)) { 61 | return (uint32_t)-1; 62 | } 63 | void* new_data = 64 | realloc(table->data, new_elems * sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); 65 | if (!new_data) { 66 | return (uint32_t)-1; 67 | } 68 | table->data = new_data; 69 | table->size = new_elems; 70 | for (uint32_t i = old_elems; i < new_elems; i++) { 71 | table->data[i] = init; 72 | } 73 | return old_elems; 74 | } 75 | 76 | #undef WASM_RT_TABLE_APINAME 77 | #undef WASM_RT_TABLE_ELEMENT_TYPE 78 | #undef WASM_RT_TABLE_TYPE -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-impl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt-impl.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) 29 | #include 30 | #include 31 | #endif 32 | 33 | #ifdef _WIN32 34 | #include 35 | #else 36 | #include 37 | #endif 38 | 39 | #ifndef NDEBUG 40 | #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__); 41 | #else 42 | #define DEBUG_PRINTF(...) 43 | #endif 44 | 45 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 46 | static bool g_signal_handler_installed = false; 47 | #ifdef _WIN32 48 | static void* g_sig_handler_handle = 0; 49 | #endif 50 | #endif 51 | 52 | #if WASM_RT_USE_SEGUE || WASM_RT_ALLOW_SEGUE 53 | // Currently Segue is used only for linux 54 | #include 55 | #ifdef __GLIBC__ 56 | #include 57 | #endif 58 | bool wasm_rt_fsgsbase_inst_supported = false; 59 | 60 | #include // For ARCH_SET_GS 61 | #include // For SYS_arch_prctl 62 | #include // For syscall 63 | #endif 64 | 65 | #if WASM_RT_SEGUE_FREE_SEGMENT 66 | WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val = NULL; 67 | #endif 68 | 69 | #if WASM_RT_STACK_DEPTH_COUNT 70 | WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; 71 | WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth; 72 | #elif WASM_RT_STACK_EXHAUSTION_HANDLER 73 | static WASM_RT_THREAD_LOCAL void* g_alt_stack = NULL; 74 | #endif 75 | 76 | WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; 77 | 78 | #ifdef WASM_RT_TRAP_HANDLER 79 | extern void WASM_RT_TRAP_HANDLER(wasm_rt_trap_t code); 80 | #endif 81 | 82 | void wasm_rt_trap(wasm_rt_trap_t code) { 83 | assert(code != WASM_RT_TRAP_NONE); 84 | #if WASM_RT_STACK_DEPTH_COUNT 85 | wasm_rt_call_stack_depth = wasm_rt_saved_call_stack_depth; 86 | #endif 87 | 88 | #ifdef WASM_RT_TRAP_HANDLER 89 | WASM_RT_TRAP_HANDLER(code); 90 | wasm_rt_unreachable(); 91 | #else 92 | WASM_RT_LONGJMP(g_wasm_rt_jmp_buf, code); 93 | #endif 94 | } 95 | 96 | #ifdef _WIN32 97 | 98 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 99 | 100 | static LONG os_signal_handler(PEXCEPTION_POINTERS info) { 101 | if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { 102 | wasm_rt_trap(WASM_RT_TRAP_OOB); 103 | } else if (info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { 104 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 105 | } 106 | return EXCEPTION_CONTINUE_SEARCH; 107 | } 108 | 109 | static void os_install_signal_handler(void) { 110 | g_sig_handler_handle = 111 | AddVectoredExceptionHandler(1 /* CALL_FIRST */, os_signal_handler); 112 | } 113 | 114 | static void os_cleanup_signal_handler(void) { 115 | RemoveVectoredExceptionHandler(g_sig_handler_handle); 116 | } 117 | 118 | #endif 119 | 120 | #else 121 | 122 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 123 | static void os_signal_handler(int sig, siginfo_t* si, void* unused) { 124 | if (si->si_code == SEGV_ACCERR) { 125 | wasm_rt_trap(WASM_RT_TRAP_OOB); 126 | } else { 127 | wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); 128 | } 129 | } 130 | 131 | static void os_install_signal_handler(void) { 132 | struct sigaction sa; 133 | memset(&sa, '\0', sizeof(sa)); 134 | sa.sa_flags = SA_SIGINFO; 135 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 136 | sa.sa_flags |= SA_ONSTACK; 137 | #endif 138 | sigemptyset(&sa.sa_mask); 139 | sa.sa_sigaction = os_signal_handler; 140 | 141 | /* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */ 142 | if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL) != 0) { 143 | perror("sigaction failed"); 144 | abort(); 145 | } 146 | } 147 | 148 | static void os_cleanup_signal_handler(void) { 149 | /* Undo what was done in os_install_signal_handler */ 150 | struct sigaction sa; 151 | memset(&sa, '\0', sizeof(sa)); 152 | sa.sa_handler = SIG_DFL; 153 | if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) { 154 | perror("sigaction failed"); 155 | abort(); 156 | } 157 | } 158 | #endif 159 | 160 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 161 | static bool os_has_altstack_installed() { 162 | /* check for altstack already in place */ 163 | stack_t ss; 164 | if (sigaltstack(NULL, &ss) != 0) { 165 | perror("sigaltstack failed"); 166 | abort(); 167 | } 168 | 169 | return !(ss.ss_flags & SS_DISABLE); 170 | } 171 | 172 | /* These routines set up an altstack to handle SIGSEGV from stack overflow. */ 173 | static void os_allocate_and_install_altstack(void) { 174 | /* verify altstack not already allocated */ 175 | assert(!g_alt_stack && 176 | "wasm-rt error: tried to re-allocate thread-local alternate stack"); 177 | 178 | /* We could check and warn if an altstack is already installed, but some 179 | * sanitizers install their own altstack, so this warning would fire 180 | * spuriously and break the test outputs. */ 181 | 182 | /* allocate altstack */ 183 | g_alt_stack = malloc(SIGSTKSZ); 184 | if (g_alt_stack == NULL) { 185 | perror("malloc failed"); 186 | abort(); 187 | } 188 | 189 | /* install altstack */ 190 | stack_t ss; 191 | ss.ss_sp = g_alt_stack; 192 | ss.ss_flags = 0; 193 | ss.ss_size = SIGSTKSZ; 194 | if (sigaltstack(&ss, NULL) != 0) { 195 | perror("sigaltstack failed"); 196 | abort(); 197 | } 198 | } 199 | 200 | static void os_disable_and_deallocate_altstack(void) { 201 | /* in debug build, verify altstack allocated */ 202 | assert(g_alt_stack && 203 | "wasm-rt error: thread-local alternate stack not allocated"); 204 | 205 | /* verify altstack was still in place */ 206 | stack_t ss; 207 | if (sigaltstack(NULL, &ss) != 0) { 208 | perror("sigaltstack failed"); 209 | abort(); 210 | } 211 | 212 | if ((!g_alt_stack) || (ss.ss_flags & SS_DISABLE) || 213 | (ss.ss_sp != g_alt_stack) || (ss.ss_size != SIGSTKSZ)) { 214 | DEBUG_PRINTF( 215 | "wasm-rt warning: alternate stack was modified unexpectedly\n"); 216 | return; 217 | } 218 | 219 | /* disable and free */ 220 | ss.ss_flags = SS_DISABLE; 221 | if (sigaltstack(&ss, NULL) != 0) { 222 | perror("sigaltstack failed"); 223 | abort(); 224 | } 225 | assert(!os_has_altstack_installed()); 226 | free(g_alt_stack); 227 | g_alt_stack = NULL; 228 | } 229 | #endif 230 | 231 | #endif 232 | 233 | void wasm_rt_init(void) { 234 | wasm_rt_init_thread(); 235 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 236 | if (!g_signal_handler_installed) { 237 | g_signal_handler_installed = true; 238 | os_install_signal_handler(); 239 | } 240 | #endif 241 | 242 | #if WASM_RT_USE_SEGUE || WASM_RT_ALLOW_SEGUE 243 | #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 18 244 | // Check for support for userspace wrgsbase instructions 245 | unsigned long val = getauxval(AT_HWCAP2); 246 | wasm_rt_fsgsbase_inst_supported = val & (1 << 1); 247 | #endif 248 | #endif 249 | 250 | assert(wasm_rt_is_initialized()); 251 | } 252 | 253 | bool wasm_rt_is_initialized(void) { 254 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 255 | if (!os_has_altstack_installed()) { 256 | return false; 257 | } 258 | #endif 259 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !WASM_RT_SHARED_WEAK 260 | return g_signal_handler_installed; 261 | #else 262 | return true; 263 | #endif 264 | } 265 | 266 | void wasm_rt_free(void) { 267 | assert(wasm_rt_is_initialized()); 268 | #if WASM_RT_INSTALL_SIGNAL_HANDLER 269 | os_cleanup_signal_handler(); 270 | g_signal_handler_installed = false; 271 | #endif 272 | wasm_rt_free_thread(); 273 | } 274 | 275 | void wasm_rt_init_thread(void) { 276 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 277 | os_allocate_and_install_altstack(); 278 | #endif 279 | } 280 | 281 | void wasm_rt_free_thread(void) { 282 | #if WASM_RT_STACK_EXHAUSTION_HANDLER 283 | os_disable_and_deallocate_altstack(); 284 | #endif 285 | } 286 | 287 | #if WASM_RT_USE_SEGUE || WASM_RT_ALLOW_SEGUE 288 | void wasm_rt_syscall_set_segue_base(void* base) { 289 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, base) != 0) { 290 | perror("wasm_rt_syscall_set_segue_base error"); 291 | abort(); 292 | } 293 | } 294 | void* wasm_rt_syscall_get_segue_base() { 295 | void* base; 296 | if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0) { 297 | perror("wasm_rt_syscall_get_segue_base error"); 298 | abort(); 299 | } 300 | return base; 301 | } 302 | #endif 303 | 304 | // Include table operations for funcref 305 | #define WASM_RT_TABLE_OPS_FUNCREF 306 | #include "wasm-rt-impl-tableops.inc" 307 | #undef WASM_RT_TABLE_OPS_FUNCREF 308 | 309 | // Include table operations for externref 310 | #define WASM_RT_TABLE_OPS_EXTERNREF 311 | #include "wasm-rt-impl-tableops.inc" 312 | #undef WASM_RT_TABLE_OPS_EXTERNREF 313 | 314 | const char* wasm_rt_strerror(wasm_rt_trap_t trap) { 315 | switch (trap) { 316 | case WASM_RT_TRAP_NONE: 317 | return "No error"; 318 | case WASM_RT_TRAP_OOB: 319 | #if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 320 | return "Out-of-bounds access in linear memory or a table, or call stack " 321 | "exhausted"; 322 | #else 323 | return "Out-of-bounds access in linear memory or a table"; 324 | case WASM_RT_TRAP_EXHAUSTION: 325 | return "Call stack exhausted"; 326 | #endif 327 | case WASM_RT_TRAP_INT_OVERFLOW: 328 | return "Integer overflow on divide or truncation"; 329 | case WASM_RT_TRAP_DIV_BY_ZERO: 330 | return "Integer divide by zero"; 331 | case WASM_RT_TRAP_INVALID_CONVERSION: 332 | return "Conversion from NaN to integer"; 333 | case WASM_RT_TRAP_UNREACHABLE: 334 | return "Unreachable instruction executed"; 335 | case WASM_RT_TRAP_CALL_INDIRECT: 336 | return "Invalid call_indirect or return_call_indirect"; 337 | case WASM_RT_TRAP_UNCAUGHT_EXCEPTION: 338 | return "Uncaught exception"; 339 | case WASM_RT_TRAP_UNALIGNED: 340 | return "Unaligned atomic memory access"; 341 | } 342 | return "invalid trap code"; 343 | } -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_H_ 18 | #define WASM_RT_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #ifndef __has_builtin 31 | #define __has_builtin(x) 0 /** Compatibility with non-clang compilers. */ 32 | #endif 33 | 34 | #if __has_builtin(__builtin_expect) 35 | #define UNLIKELY(x) __builtin_expect(!!(x), 0) 36 | #define LIKELY(x) __builtin_expect(!!(x), 1) 37 | #else 38 | #define UNLIKELY(x) (x) 39 | #define LIKELY(x) (x) 40 | #endif 41 | 42 | #if __has_builtin(__builtin_memcpy) 43 | #define wasm_rt_memcpy __builtin_memcpy 44 | #else 45 | #define wasm_rt_memcpy memcpy 46 | #endif 47 | 48 | #if __has_builtin(__builtin_unreachable) 49 | #define wasm_rt_unreachable __builtin_unreachable 50 | #else 51 | #define wasm_rt_unreachable abort 52 | #endif 53 | 54 | #ifdef __STDC_VERSION__ 55 | #if __STDC_VERSION__ >= 201112L 56 | #define WASM_RT_C11_AVAILABLE 57 | #endif 58 | #endif 59 | 60 | /** 61 | * Many devices don't implement the C11 threads.h. We use CriticalSection APIs 62 | * for Windows and pthreads on other platforms where threads are not available. 63 | */ 64 | #ifdef WASM_RT_C11_AVAILABLE 65 | 66 | #if defined(_WIN32) 67 | #include 68 | #define WASM_RT_MUTEX CRITICAL_SECTION 69 | #define WASM_RT_USE_CRITICALSECTION 1 70 | #elif defined(__APPLE__) || defined(__STDC_NO_THREADS__) 71 | #include 72 | #define WASM_RT_MUTEX pthread_mutex_t 73 | #define WASM_RT_USE_PTHREADS 1 74 | #else 75 | #include 76 | #define WASM_RT_MUTEX mtx_t 77 | #define WASM_RT_USE_C11THREADS 1 78 | #endif 79 | 80 | #endif 81 | 82 | #ifdef _MSC_VER 83 | #define WASM_RT_THREAD_LOCAL __declspec(thread) 84 | #elif defined(WASM_RT_C11_AVAILABLE) 85 | #define WASM_RT_THREAD_LOCAL _Thread_local 86 | #else 87 | #define WASM_RT_THREAD_LOCAL 88 | #endif 89 | 90 | /** 91 | * If enabled, perform additional sanity checks in the generated wasm2c code and 92 | * wasm2c runtime. This is useful to enable on debug builds. 93 | */ 94 | #ifndef WASM_RT_SANITY_CHECKS 95 | #define WASM_RT_SANITY_CHECKS 0 96 | #endif 97 | 98 | /** 99 | * Backward compatibility: Convert the previously exposed 100 | * WASM_RT_MEMCHECK_SIGNAL_HANDLER macro to the ALLOCATION and CHECK macros that 101 | * are now used. 102 | */ 103 | #if defined(WASM_RT_MEMCHECK_SIGNAL_HANDLER) 104 | 105 | #if WASM_RT_MEMCHECK_SIGNAL_HANDLER 106 | #define WASM_RT_USE_MMAP 1 107 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 108 | #else 109 | #define WASM_RT_USE_MMAP 0 110 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 111 | #endif 112 | 113 | #warning \ 114 | "WASM_RT_MEMCHECK_SIGNAL_HANDLER has been deprecated in favor of WASM_RT_USE_MMAP and WASM_RT_MEMORY_CHECK_* macros" 115 | #endif 116 | 117 | /** 118 | * Specify if we use OR mmap/mprotect (+ Windows equivalents) OR malloc/realloc 119 | * for the Wasm memory allocation and growth. mmap/mprotect guarantees memory 120 | * will grow without being moved, while malloc ensures the virtual memory is 121 | * consumed only as needed, but may relocate the memory to handle memory 122 | * fragmentation. 123 | * 124 | * This defaults to malloc on 32-bit platforms or if memory64 support is needed. 125 | * It defaults to mmap on 64-bit platforms assuming memory64 support is not 126 | * needed (so we can use the guard based range checks below). 127 | */ 128 | #ifndef WASM_RT_USE_MMAP 129 | #if UINTPTR_MAX > 0xffffffff && !SUPPORT_MEMORY64 130 | #define WASM_RT_USE_MMAP 1 131 | #else 132 | #define WASM_RT_USE_MMAP 0 133 | #endif 134 | #endif 135 | 136 | /** 137 | * Set the range checking strategy for Wasm memories. 138 | * 139 | * GUARD_PAGES: memory accesses rely on unmapped pages/guard pages to trap 140 | * out-of-bound accesses. 141 | * 142 | * BOUNDS_CHECK: memory accesses are checked with explicit bounds checks. 143 | * 144 | * This defaults to GUARD_PAGES as this is the fasest option, iff the 145 | * requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy, 146 | * no 64-bit memories, no big-endian --- are met. This falls back to BOUNDS 147 | * otherwise. 148 | */ 149 | 150 | /** Check if Guard checks are supported */ 151 | #if UINTPTR_MAX > 0xffffffff && WASM_RT_USE_MMAP && !SUPPORT_MEMORY64 && \ 152 | !WABT_BIG_ENDIAN 153 | #define WASM_RT_GUARD_PAGES_SUPPORTED 1 154 | #else 155 | #define WASM_RT_GUARD_PAGES_SUPPORTED 0 156 | #endif 157 | 158 | /** Specify defaults for memory checks if unspecified */ 159 | #if !defined(WASM_RT_MEMCHECK_GUARD_PAGES) && \ 160 | !defined(WASM_RT_MEMCHECK_BOUNDS_CHECK) 161 | #if WASM_RT_GUARD_PAGES_SUPPORTED 162 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 163 | #else 164 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 165 | #endif 166 | #endif 167 | 168 | /** Ensure the macros are defined */ 169 | #ifndef WASM_RT_MEMCHECK_GUARD_PAGES 170 | #define WASM_RT_MEMCHECK_GUARD_PAGES 0 171 | #endif 172 | #ifndef WASM_RT_MEMCHECK_BOUNDS_CHECK 173 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 0 174 | #endif 175 | 176 | /** Sanity check the use of guard pages */ 177 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_GUARD_PAGES_SUPPORTED 178 | #error \ 179 | "WASM_RT_MEMCHECK_GUARD_PAGES not supported on this platform/configuration" 180 | #endif 181 | 182 | #if WASM_RT_MEMCHECK_GUARD_PAGES && WASM_RT_MEMCHECK_BOUNDS_CHECK 183 | #error \ 184 | "Cannot use both WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 185 | 186 | #elif !WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_MEMCHECK_BOUNDS_CHECK 187 | #error \ 188 | "Must choose at least one from WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 189 | #endif 190 | 191 | /** 192 | * Some configurations above require the Wasm runtime to install a signal 193 | * handler. However, this can be explicitly disallowed by the host using 194 | * WASM_RT_SKIP_SIGNAL_RECOVERY. In this case, when the wasm code encounters an 195 | * OOB access, it may either trap or abort. 196 | */ 197 | #ifndef WASM_RT_SKIP_SIGNAL_RECOVERY 198 | #define WASM_RT_SKIP_SIGNAL_RECOVERY 0 199 | #endif 200 | 201 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_SKIP_SIGNAL_RECOVERY 202 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 1 203 | #else 204 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 0 205 | #endif 206 | 207 | #ifndef WASM_RT_SHARED_WEAK 208 | #define WASM_RT_SHARED_WEAK 0 209 | #endif 210 | 211 | /** 212 | * This macro, if defined to 1 (i.e., allows the "segue" optimization), allows 213 | * Wasm2c to use segment registers to speedup access to the linear heap. Note 214 | * that even if allowed in this way, the segment registers would only be used if 215 | * Wasm2c output is compiled for a suitable architecture and OS and the produces 216 | * C file is compiled by supported compilers. The extact restrictions are listed 217 | * in detail in src/template/wasm2c.declarations.c 218 | */ 219 | #ifndef WASM_RT_ALLOW_SEGUE 220 | #define WASM_RT_ALLOW_SEGUE 0 221 | #endif 222 | 223 | /** 224 | * The segue optimization restores x86 segments to their old values when exiting 225 | * wasm2c code. If WASM_RT_SEGUE_FREE_SEGMENT is defined, wasm2c assumes it has 226 | * exclusive use of the segment and optimizes performance in two ways. First, it 227 | * does not restore the "old" value of the segment during exits. Second, wasm2c 228 | * only sets the segment register if the value has changed since the last time 229 | * it was set. 230 | */ 231 | #ifndef WASM_RT_SEGUE_FREE_SEGMENT 232 | #define WASM_RT_SEGUE_FREE_SEGMENT 0 233 | #endif 234 | 235 | /** 236 | * This macro, if defined, allows the embedder to disable all stack exhaustion 237 | * checks. This a non conformant configuration, i.e., this does not respect 238 | * Wasm's specification, and may compromise security. Use with caution. 239 | */ 240 | #ifndef WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 241 | #define WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 0 242 | #endif 243 | 244 | /** 245 | * We need to detect and trap stack overflows. If we use a signal handler on 246 | * POSIX systems, this can detect call stack overflows. On windows, or platforms 247 | * without a signal handler, we use stack depth counting. 248 | */ 249 | #if !defined(WASM_RT_STACK_DEPTH_COUNT) && \ 250 | !defined(WASM_RT_STACK_EXHAUSTION_HANDLER) && \ 251 | !WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 252 | 253 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) 254 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 1 255 | #else 256 | #define WASM_RT_STACK_DEPTH_COUNT 1 257 | #endif 258 | 259 | #endif 260 | 261 | /** Ensure the stack macros are defined */ 262 | #ifndef WASM_RT_STACK_DEPTH_COUNT 263 | #define WASM_RT_STACK_DEPTH_COUNT 0 264 | #endif 265 | #ifndef WASM_RT_STACK_EXHAUSTION_HANDLER 266 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 0 267 | #endif 268 | 269 | #if WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 270 | 271 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) != 0 272 | #error \ 273 | "Cannot specify WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION along with WASM_RT_STACK_EXHAUSTION_HANDLER or WASM_RT_STACK_DEPTH_COUNT" 274 | #endif 275 | 276 | #else 277 | 278 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) > 1 279 | #error \ 280 | "Cannot specify multiple options from WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 281 | #elif (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) == 0 282 | #error \ 283 | "Must specify one of WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 284 | #endif 285 | 286 | #endif 287 | 288 | #if WASM_RT_STACK_EXHAUSTION_HANDLER && !WASM_RT_INSTALL_SIGNAL_HANDLER 289 | #error \ 290 | "WASM_RT_STACK_EXHAUSTION_HANDLER can only be used if WASM_RT_INSTALL_SIGNAL_HANDLER is enabled" 291 | #endif 292 | 293 | #if WASM_RT_STACK_DEPTH_COUNT 294 | /** 295 | * When the signal handler cannot be used to detect stack overflows, stack depth 296 | * is limited explicitly. The maximum stack depth before trapping can be 297 | * configured by defining this symbol before including wasm-rt when building the 298 | * generated c files, for example: 299 | * 300 | * ``` 301 | * cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o 302 | * ``` 303 | */ 304 | #ifndef WASM_RT_MAX_CALL_STACK_DEPTH 305 | #define WASM_RT_MAX_CALL_STACK_DEPTH 500 306 | #endif 307 | 308 | /** Current call stack depth. */ 309 | extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; 310 | 311 | #endif 312 | 313 | #if WASM_RT_USE_SEGUE || WASM_RT_ALLOW_SEGUE 314 | /** 315 | * The segue optimization uses x86 segments to point to a linear memory. If 316 | * used, the runtime must query whether it can use the fast userspace wrgsbase 317 | * instructions or whether it must invoke syscalls to set the segment base, 318 | * depending on the supported CPU features. The result of this query is saved in 319 | * this variable. 320 | */ 321 | extern bool wasm_rt_fsgsbase_inst_supported; 322 | /** 323 | * If fast userspace wrgsbase instructions don't exist, the runtime most provide 324 | * a function that invokes the OS' underlying syscall to set the segment base. 325 | */ 326 | void wasm_rt_syscall_set_segue_base(void* base); 327 | /** 328 | * If fast userspace rdgsbase instructions don't exist, the runtime most provide 329 | * a function that invokes the OS' underlying syscall to get the segment base. 330 | */ 331 | void* wasm_rt_syscall_get_segue_base(); 332 | /** 333 | * If WASM_RT_SEGUE_FREE_SEGMENT is defined, we must only set the segment 334 | * register if it was changed since the last time it was set. The last value set 335 | * on the segment register is stored in this variable. 336 | */ 337 | #if WASM_RT_SEGUE_FREE_SEGMENT 338 | extern WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val; 339 | #endif 340 | #endif 341 | 342 | #if defined(_MSC_VER) 343 | #define WASM_RT_NO_RETURN __declspec(noreturn) 344 | #else 345 | #define WASM_RT_NO_RETURN __attribute__((noreturn)) 346 | #endif 347 | 348 | #if defined(__APPLE__) && WASM_RT_STACK_EXHAUSTION_HANDLER 349 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1 350 | #else 351 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0 352 | #endif 353 | 354 | /** Reason a trap occurred. Provide this to `wasm_rt_trap`. */ 355 | typedef enum { 356 | WASM_RT_TRAP_NONE, /** No error. */ 357 | WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory or a table. */ 358 | WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */ 359 | WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */ 360 | WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */ 361 | WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */ 362 | WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */ 363 | WASM_RT_TRAP_UNCAUGHT_EXCEPTION, /** Exception thrown and not caught. */ 364 | WASM_RT_TRAP_UNALIGNED, /** Unaligned atomic instruction executed. */ 365 | #if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 366 | WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB, 367 | #else 368 | WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */ 369 | #endif 370 | } wasm_rt_trap_t; 371 | 372 | /** Value types. Used to define function signatures. */ 373 | typedef enum { 374 | WASM_RT_I32, 375 | WASM_RT_I64, 376 | WASM_RT_F32, 377 | WASM_RT_F64, 378 | WASM_RT_V128, 379 | WASM_RT_FUNCREF, 380 | WASM_RT_EXTERNREF, 381 | } wasm_rt_type_t; 382 | 383 | /** 384 | * A generic function pointer type, both for Wasm functions (`code`) 385 | * and host functions (`hostcode`). All function pointers are stored 386 | * in this canonical form, but must be cast to their proper signature 387 | * to call. 388 | */ 389 | typedef void (*wasm_rt_function_ptr_t)(void); 390 | 391 | /** 392 | * A pointer to a "tail-callee" function, called by a tail-call 393 | * trampoline or by another tail-callee function. (The definition uses a 394 | * single-member struct to allow a recursive definition.) 395 | */ 396 | typedef struct wasm_rt_tailcallee_t { 397 | void (*fn)(void** instance_ptr, 398 | void* tail_call_stack, 399 | struct wasm_rt_tailcallee_t* next); 400 | } wasm_rt_tailcallee_t; 401 | 402 | /** 403 | * The type of a function (an arbitrary number of param and result types). 404 | * This is represented as an opaque 256-bit ID. 405 | */ 406 | typedef const char* wasm_rt_func_type_t; 407 | 408 | /** 409 | * A function instance (the runtime representation of a function). 410 | * These can be stored in tables of type funcref, or used as values. 411 | */ 412 | typedef struct { 413 | /** The function's type. */ 414 | wasm_rt_func_type_t func_type; 415 | /** 416 | * The function. The embedder must know the actual C signature of the function 417 | * and cast to it before calling. 418 | */ 419 | wasm_rt_function_ptr_t func; 420 | /** An alternate version of the function to be used when tail-called. */ 421 | wasm_rt_tailcallee_t func_tailcallee; 422 | /** 423 | * A function instance is a closure of the function over an instance 424 | * of the originating module. The module_instance element will be passed into 425 | * the function at runtime. 426 | */ 427 | void* module_instance; 428 | } wasm_rt_funcref_t; 429 | 430 | /** Default (null) value of a funcref */ 431 | #define wasm_rt_funcref_null_value \ 432 | ((wasm_rt_funcref_t){NULL, NULL, {NULL}, NULL}) 433 | 434 | /** The type of an external reference (opaque to WebAssembly). */ 435 | typedef void* wasm_rt_externref_t; 436 | 437 | /** Default (null) value of an externref */ 438 | #define wasm_rt_externref_null_value ((wasm_rt_externref_t){NULL}) 439 | 440 | /** A Memory object. */ 441 | typedef struct { 442 | /** The linear memory data, with a byte length of `size`. */ 443 | uint8_t* data; 444 | /** The current page count for this Memory object. */ 445 | uint64_t pages; 446 | /** 447 | * The maximum page count for this Memory object. If there is no maximum, 448 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 449 | */ 450 | uint64_t max_pages; 451 | /** The current size of the linear memory, in bytes. */ 452 | uint64_t size; 453 | /** Is this memory indexed by u64 (as opposed to default u32) */ 454 | bool is64; 455 | } wasm_rt_memory_t; 456 | 457 | #ifdef WASM_RT_C11_AVAILABLE 458 | /** A shared Memory object. */ 459 | typedef struct { 460 | /** 461 | * The linear memory data, with a byte length of `size`. The memory is marked 462 | * atomic as it is shared and may have to be accessed with different memory 463 | * orders --- sequential when being accessed atomically, relaxed otherwise. 464 | * Unfortunately, the C standard does not state what happens if there are 465 | * overlaps in two memory accesses which have a memory order, e.g., an 466 | * atomic32 being read from the same location an atomic64 is read. One way to 467 | * prevent optimizations from assuming non-overlapping behavior as typically 468 | * done in C is to mark the memory as volatile. Thus the memory is atomic and 469 | * volatile. 470 | */ 471 | _Atomic volatile uint8_t* data; 472 | /** The current page count for this Memory object. */ 473 | uint64_t pages; 474 | /** 475 | * The maximum page count for this Memory object. If there is no maximum, 476 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 477 | */ 478 | uint64_t max_pages; 479 | /** The current size of the linear memory, in bytes. */ 480 | uint64_t size; 481 | /** Is this memory indexed by u64 (as opposed to default u32) */ 482 | bool is64; 483 | /** Lock used to ensure operations such as memory grow are threadsafe */ 484 | WASM_RT_MUTEX mem_lock; 485 | } wasm_rt_shared_memory_t; 486 | #endif 487 | 488 | /** A Table of type funcref. */ 489 | typedef struct { 490 | /** The table element data, with an element count of `size`. */ 491 | wasm_rt_funcref_t* data; 492 | /** 493 | * The maximum element count of this Table object. If there is no maximum, 494 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 495 | */ 496 | uint32_t max_size; 497 | /** The current element count of the table. */ 498 | uint32_t size; 499 | } wasm_rt_funcref_table_t; 500 | 501 | /** A Table of type externref. */ 502 | typedef struct { 503 | /** The table element data, with an element count of `size`. */ 504 | wasm_rt_externref_t* data; 505 | /** 506 | * The maximum element count of this Table object. If there is no maximum, 507 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 508 | */ 509 | uint32_t max_size; 510 | /** The current element count of the table. */ 511 | uint32_t size; 512 | } wasm_rt_externref_table_t; 513 | 514 | /** Initialize the runtime. */ 515 | void wasm_rt_init(void); 516 | 517 | /** Is the runtime initialized? */ 518 | bool wasm_rt_is_initialized(void); 519 | 520 | /** Free the runtime's state. */ 521 | void wasm_rt_free(void); 522 | 523 | /* 524 | * Initialize the multithreaded runtime for a given thread. Must be 525 | * called by each thread (other than the one that called wasm_rt_init) 526 | * before initializing a Wasm module or calling an exported 527 | * function. 528 | */ 529 | void wasm_rt_init_thread(void); 530 | 531 | /* 532 | * Free the individual thread's state. 533 | */ 534 | void wasm_rt_free_thread(void); 535 | 536 | /** A hardened jmp_buf that allows checking for initialization before use */ 537 | typedef struct { 538 | /** Is the jmp buf intialized? */ 539 | bool initialized; 540 | /** jmp_buf contents */ 541 | jmp_buf buffer; 542 | } wasm_rt_jmp_buf; 543 | 544 | #ifndef _WIN32 545 | #define WASM_RT_SETJMP_SETBUF(buf) sigsetjmp(buf, 1) 546 | #else 547 | #define WASM_RT_SETJMP_SETBUF(buf) setjmp(buf) 548 | #endif 549 | 550 | #define WASM_RT_SETJMP(buf) \ 551 | ((buf).initialized = true, WASM_RT_SETJMP_SETBUF((buf).buffer)) 552 | 553 | #ifndef _WIN32 554 | #define WASM_RT_LONGJMP_UNCHECKED(buf, val) siglongjmp(buf, val) 555 | #else 556 | #define WASM_RT_LONGJMP_UNCHECKED(buf, val) longjmp(buf, val) 557 | #endif 558 | 559 | #define WASM_RT_LONGJMP(buf, val) \ 560 | /** Abort on failure as this may be called in the trap handler */ \ 561 | if (!((buf).initialized)) \ 562 | abort(); \ 563 | (buf).initialized = false; \ 564 | WASM_RT_LONGJMP_UNCHECKED((buf).buffer, val) 565 | 566 | /** 567 | * Stop execution immediately and jump back to the call to `wasm_rt_impl_try`. 568 | * The result of `wasm_rt_impl_try` will be the provided trap reason. 569 | * 570 | * This is typically called by the generated code, and not the embedder. 571 | */ 572 | WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t); 573 | 574 | /** Return a human readable error string based on a trap type. */ 575 | const char* wasm_rt_strerror(wasm_rt_trap_t trap); 576 | 577 | #define wasm_rt_try(target) WASM_RT_SETJMP(target) 578 | 579 | /** 580 | * Initialize a Memory object with an initial page size of `initial_pages` and 581 | * a maximum page size of `max_pages`, indexed with an i32 or i64. 582 | * 583 | * ``` 584 | * wasm_rt_memory_t my_memory; 585 | * // 1 initial page (65536 bytes), and a maximum of 2 pages, 586 | * // indexed with an i32 587 | * wasm_rt_allocate_memory(&my_memory, 1, 2, false); 588 | * ``` 589 | */ 590 | void wasm_rt_allocate_memory(wasm_rt_memory_t*, 591 | uint64_t initial_pages, 592 | uint64_t max_pages, 593 | bool is64); 594 | 595 | /** 596 | * Grow a Memory object by `pages`, and return the previous page count. If 597 | * this new page count is greater than the maximum page count, the grow fails 598 | * and 0xffffffffu (UINT32_MAX) is returned instead. 599 | * 600 | * ``` 601 | * wasm_rt_memory_t my_memory; 602 | * ... 603 | * // Grow memory by 10 pages. 604 | * uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10); 605 | * if (old_page_size == UINT32_MAX) { 606 | * // Failed to grow memory. 607 | * } 608 | * ``` 609 | */ 610 | uint64_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint64_t pages); 611 | 612 | /** Free a Memory object. */ 613 | void wasm_rt_free_memory(wasm_rt_memory_t*); 614 | 615 | #ifdef WASM_RT_C11_AVAILABLE 616 | /** Shared memory version of wasm_rt_allocate_memory */ 617 | void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, 618 | uint64_t initial_pages, 619 | uint64_t max_pages, 620 | bool is64); 621 | 622 | /** Shared memory version of wasm_rt_grow_memory */ 623 | uint64_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint64_t pages); 624 | 625 | /** Shared memory version of wasm_rt_free_memory */ 626 | void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*); 627 | #endif 628 | 629 | /** 630 | * Initialize a funcref Table object with an element count of `elements` and a 631 | * maximum size of `max_elements`. 632 | * 633 | * ``` 634 | * wasm_rt_funcref_table_t my_table; 635 | * // 5 elements and a maximum of 10 elements. 636 | * wasm_rt_allocate_funcref_table(&my_table, 5, 10); 637 | * ``` 638 | */ 639 | void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t*, 640 | uint32_t elements, 641 | uint32_t max_elements); 642 | 643 | /** Free a funcref Table object. */ 644 | void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t*); 645 | 646 | /** 647 | * Initialize an externref Table object with an element count 648 | * of `elements` and a maximum size of `max_elements`. 649 | * Usage as per wasm_rt_allocate_funcref_table. 650 | */ 651 | void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*, 652 | uint32_t elements, 653 | uint32_t max_elements); 654 | 655 | /** Free an externref Table object. */ 656 | void wasm_rt_free_externref_table(wasm_rt_externref_table_t*); 657 | 658 | /** 659 | * Grow a Table object by `delta` elements (giving the new elements the value 660 | * `init`), and return the previous element count. If this new element count is 661 | * greater than the maximum element count, the grow fails and 0xffffffffu 662 | * (UINT32_MAX) is returned instead. 663 | */ 664 | uint32_t wasm_rt_grow_funcref_table(wasm_rt_funcref_table_t*, 665 | uint32_t delta, 666 | wasm_rt_funcref_t init); 667 | uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t*, 668 | uint32_t delta, 669 | wasm_rt_externref_t init); 670 | 671 | #ifdef __cplusplus 672 | } 673 | #endif 674 | 675 | #endif /* WASM_RT_H_ */ -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-mem-impl-helper.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file is used as a template to generate code for regular memories or for 18 | // shared memories. For this, the file must be included after defining either 19 | // WASM_RT_MEM_OPS or WASM_RT_MEM_OPS_SHARED. 20 | 21 | #if defined(WASM_RT_MEM_OPS) && defined(WASM_RT_MEM_OPS_SHARED) 22 | #error \ 23 | "Expected only one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" 24 | #elif !defined(WASM_RT_MEM_OPS) && !defined(WASM_RT_MEM_OPS_SHARED) 25 | #error \ 26 | "Expected one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" 27 | #endif 28 | 29 | // Shared memory operations are defined only if we have C11 30 | #if defined(WASM_RT_MEM_OPS) || \ 31 | (defined(WASM_RT_MEM_OPS_SHARED) && defined(WASM_RT_C11_AVAILABLE)) 32 | 33 | #ifdef WASM_RT_MEM_OPS 34 | 35 | // Memory operations on wasm_rt_memory_t 36 | #define MEMORY_TYPE wasm_rt_memory_t 37 | #define MEMORY_API_NAME(name) name 38 | #define MEMORY_CELL_TYPE uint8_t* 39 | #define MEMORY_LOCK_VAR_INIT(name) 40 | #define MEMORY_LOCK_AQUIRE(name) 41 | #define MEMORY_LOCK_RELEASE(name) 42 | 43 | #else 44 | 45 | // Memory operations on wasm_rt_shared_memory_t 46 | #define MEMORY_TYPE wasm_rt_shared_memory_t 47 | #define MEMORY_API_NAME(name) name##_shared 48 | #define MEMORY_CELL_TYPE _Atomic volatile uint8_t* 49 | 50 | #if WASM_RT_USE_C11THREADS 51 | #define MEMORY_LOCK_VAR_INIT(name) C11_MEMORY_LOCK_VAR_INIT(name) 52 | #define MEMORY_LOCK_AQUIRE(name) C11_MEMORY_LOCK_AQUIRE(name) 53 | #define MEMORY_LOCK_RELEASE(name) C11_MEMORY_LOCK_RELEASE(name) 54 | #elif WASM_RT_USE_PTHREADS 55 | #define MEMORY_LOCK_VAR_INIT(name) PTHREAD_MEMORY_LOCK_VAR_INIT(name) 56 | #define MEMORY_LOCK_AQUIRE(name) PTHREAD_MEMORY_LOCK_AQUIRE(name) 57 | #define MEMORY_LOCK_RELEASE(name) PTHREAD_MEMORY_LOCK_RELEASE(name) 58 | #elif WASM_RT_USE_CRITICALSECTION 59 | #define MEMORY_LOCK_VAR_INIT(name) WIN_MEMORY_LOCK_VAR_INIT(name) 60 | #define MEMORY_LOCK_AQUIRE(name) WIN_MEMORY_LOCK_AQUIRE(name) 61 | #define MEMORY_LOCK_RELEASE(name) WIN_MEMORY_LOCK_RELEASE(name) 62 | #endif 63 | 64 | #endif 65 | 66 | void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, 67 | uint64_t initial_pages, 68 | uint64_t max_pages, 69 | bool is64) { 70 | uint64_t byte_length = initial_pages * WASM_PAGE_SIZE; 71 | memory->size = byte_length; 72 | memory->pages = initial_pages; 73 | memory->max_pages = max_pages; 74 | memory->is64 = is64; 75 | MEMORY_LOCK_VAR_INIT(memory->mem_lock); 76 | 77 | #if WASM_RT_USE_MMAP 78 | const uint64_t mmap_size = 79 | get_alloc_size_for_mmap(memory->max_pages, memory->is64); 80 | void* addr = os_mmap(mmap_size); 81 | if (!addr) { 82 | os_print_last_error("os_mmap failed."); 83 | abort(); 84 | } 85 | int ret = os_mprotect(addr, byte_length); 86 | if (ret != 0) { 87 | os_print_last_error("os_mprotect failed."); 88 | abort(); 89 | } 90 | memory->data = addr; 91 | #else 92 | memory->data = calloc(byte_length, 1); 93 | #endif 94 | } 95 | 96 | static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory, 97 | uint64_t delta) { 98 | uint64_t old_pages = memory->pages; 99 | uint64_t new_pages = memory->pages + delta; 100 | if (new_pages == 0) { 101 | return 0; 102 | } 103 | if (new_pages < old_pages || new_pages > memory->max_pages) { 104 | return (uint64_t)-1; 105 | } 106 | uint64_t old_size = old_pages * WASM_PAGE_SIZE; 107 | uint64_t new_size = new_pages * WASM_PAGE_SIZE; 108 | uint64_t delta_size = delta * WASM_PAGE_SIZE; 109 | #if WASM_RT_USE_MMAP 110 | MEMORY_CELL_TYPE new_data = memory->data; 111 | int ret = os_mprotect((void*)(new_data + old_size), delta_size); 112 | if (ret != 0) { 113 | return (uint64_t)-1; 114 | } 115 | #else 116 | MEMORY_CELL_TYPE new_data = realloc((void*)memory->data, new_size); 117 | if (new_data == NULL) { 118 | return (uint64_t)-1; 119 | } 120 | #if !WABT_BIG_ENDIAN 121 | memset((void*)(new_data + old_size), 0, delta_size); 122 | #endif 123 | #endif 124 | #if WABT_BIG_ENDIAN 125 | memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size); 126 | memset((void*)new_data, 0, delta_size); 127 | #endif 128 | memory->pages = new_pages; 129 | memory->size = new_size; 130 | memory->data = new_data; 131 | return old_pages; 132 | } 133 | 134 | uint64_t MEMORY_API_NAME(wasm_rt_grow_memory)(MEMORY_TYPE* memory, 135 | uint64_t delta) { 136 | MEMORY_LOCK_AQUIRE(memory->mem_lock); 137 | uint64_t ret = MEMORY_API_NAME(grow_memory_impl)(memory, delta); 138 | MEMORY_LOCK_RELEASE(memory->mem_lock); 139 | #ifdef WASM_RT_GROW_FAILED_HANDLER 140 | if (ret == (uint64_t)-1) { 141 | WASM_RT_GROW_FAILED_HANDLER(); 142 | } 143 | #endif 144 | return ret; 145 | } 146 | 147 | void MEMORY_API_NAME(wasm_rt_free_memory)(MEMORY_TYPE* memory) { 148 | #if WASM_RT_USE_MMAP 149 | const uint64_t mmap_size = 150 | get_alloc_size_for_mmap(memory->max_pages, memory->is64); 151 | os_munmap((void*)memory->data, mmap_size); // ignore error 152 | #else 153 | free((void*)memory->data); 154 | #endif 155 | } 156 | 157 | #undef MEMORY_LOCK_RELEASE 158 | #undef MEMORY_LOCK_AQUIRE 159 | #undef MEMORY_LOCK_VAR_INIT 160 | #undef MEMORY_CELL_TYPE 161 | #undef MEMORY_API_NAME 162 | #undef MEMORY_TYPE 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt-mem-impl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "wasm-rt-impl.h" 18 | 19 | #include 20 | #include 21 | 22 | #ifdef _WIN32 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | #define WASM_PAGE_SIZE 65536 29 | 30 | #ifdef WASM_RT_GROW_FAILED_HANDLER 31 | extern void WASM_RT_GROW_FAILED_HANDLER(); 32 | #endif 33 | 34 | #define C11_MEMORY_LOCK_VAR_INIT(name) \ 35 | if (mtx_init(&(name), mtx_plain) != thrd_success) { \ 36 | fprintf(stderr, "Lock init failed\n"); \ 37 | abort(); \ 38 | } 39 | #define C11_MEMORY_LOCK_AQUIRE(name) \ 40 | if (mtx_lock(&(name)) != thrd_success) { \ 41 | fprintf(stderr, "Lock acquire failed\n"); \ 42 | abort(); \ 43 | } 44 | #define C11_MEMORY_LOCK_RELEASE(name) \ 45 | if (mtx_unlock(&(name)) != thrd_success) { \ 46 | fprintf(stderr, "Lock release failed\n"); \ 47 | abort(); \ 48 | } 49 | 50 | #define PTHREAD_MEMORY_LOCK_VAR_INIT(name) \ 51 | if (pthread_mutex_init(&(name), NULL) != 0) { \ 52 | fprintf(stderr, "Lock init failed\n"); \ 53 | abort(); \ 54 | } 55 | #define PTHREAD_MEMORY_LOCK_AQUIRE(name) \ 56 | if (pthread_mutex_lock(&(name)) != 0) { \ 57 | fprintf(stderr, "Lock acquire failed\n"); \ 58 | abort(); \ 59 | } 60 | #define PTHREAD_MEMORY_LOCK_RELEASE(name) \ 61 | if (pthread_mutex_unlock(&(name)) != 0) { \ 62 | fprintf(stderr, "Lock release failed\n"); \ 63 | abort(); \ 64 | } 65 | 66 | #define WIN_MEMORY_LOCK_VAR_INIT(name) InitializeCriticalSection(&(name)) 67 | #define WIN_MEMORY_LOCK_AQUIRE(name) EnterCriticalSection(&(name)) 68 | #define WIN_MEMORY_LOCK_RELEASE(name) LeaveCriticalSection(&(name)) 69 | 70 | #if WASM_RT_USE_MMAP 71 | 72 | #ifdef _WIN32 73 | static void* os_mmap(size_t size) { 74 | void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); 75 | return ret; 76 | } 77 | 78 | static int os_munmap(void* addr, size_t size) { 79 | // Windows can only unmap the whole mapping 80 | (void)size; /* unused */ 81 | BOOL succeeded = VirtualFree(addr, 0, MEM_RELEASE); 82 | return succeeded ? 0 : -1; 83 | } 84 | 85 | static int os_mprotect(void* addr, size_t size) { 86 | if (size == 0) { 87 | return 0; 88 | } 89 | void* ret = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); 90 | if (ret == addr) { 91 | return 0; 92 | } 93 | VirtualFree(addr, 0, MEM_RELEASE); 94 | return -1; 95 | } 96 | 97 | static void os_print_last_error(const char* msg) { 98 | DWORD errorMessageID = GetLastError(); 99 | if (errorMessageID != 0) { 100 | LPSTR messageBuffer = 0; 101 | // The api creates the buffer that holds the message 102 | size_t size = FormatMessageA( 103 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 104 | FORMAT_MESSAGE_IGNORE_INSERTS, 105 | NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 106 | (LPSTR)&messageBuffer, 0, NULL); 107 | (void)size; 108 | printf("%s. %s\n", msg, messageBuffer); 109 | LocalFree(messageBuffer); 110 | } else { 111 | printf("%s. No error code.\n", msg); 112 | } 113 | } 114 | 115 | #else 116 | static void* os_mmap(size_t size) { 117 | int map_prot = PROT_NONE; 118 | int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; 119 | uint8_t* addr = mmap(NULL, size, map_prot, map_flags, -1, 0); 120 | if (addr == MAP_FAILED) 121 | return NULL; 122 | return addr; 123 | } 124 | 125 | static int os_munmap(void* addr, size_t size) { 126 | return munmap(addr, size); 127 | } 128 | 129 | static int os_mprotect(void* addr, size_t size) { 130 | return mprotect(addr, size, PROT_READ | PROT_WRITE); 131 | } 132 | 133 | static void os_print_last_error(const char* msg) { 134 | perror(msg); 135 | } 136 | 137 | #endif 138 | 139 | static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) { 140 | assert(!is64 && "memory64 is not yet compatible with WASM_RT_USE_MMAP"); 141 | #if WASM_RT_MEMCHECK_GUARD_PAGES 142 | /* Reserve 8GiB. */ 143 | const uint64_t max_size = 0x200000000ul; 144 | return max_size; 145 | #else 146 | if (max_pages != 0) { 147 | const uint64_t max_size = max_pages * WASM_PAGE_SIZE; 148 | return max_size; 149 | } 150 | 151 | /* Reserve 4GiB. */ 152 | const uint64_t max_size = 0x100000000ul; 153 | return max_size; 154 | #endif 155 | } 156 | 157 | #endif 158 | 159 | // Include operations for memory 160 | #define WASM_RT_MEM_OPS 161 | #include "wasm-rt-mem-impl-helper.inc" 162 | #undef WASM_RT_MEM_OPS 163 | 164 | // Include operations for shared memory 165 | #define WASM_RT_MEM_OPS_SHARED 166 | #include "wasm-rt-mem-impl-helper.inc" 167 | #undef WASM_RT_MEM_OPS_SHARED 168 | 169 | #undef C11_MEMORY_LOCK_VAR_INIT 170 | #undef C11_MEMORY_LOCK_AQUIRE 171 | #undef C11_MEMORY_LOCK_RELEASE 172 | #undef PTHREAD_MEMORY_LOCK_VAR_INIT 173 | #undef PTHREAD_MEMORY_LOCK_AQUIRE 174 | #undef PTHREAD_MEMORY_LOCK_RELEASE 175 | #undef WIN_MEMORY_LOCK_VAR_INIT 176 | #undef WIN_MEMORY_LOCK_AQUIRE 177 | #undef WIN_MEMORY_LOCK_RELEASE 178 | #undef WASM_PAGE_SIZE -------------------------------------------------------------------------------- /cpp/wasm-rt/wasm-rt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 WebAssembly Community Group participants 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef WASM_RT_H_ 18 | #define WASM_RT_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #ifndef __has_builtin 31 | #define __has_builtin(x) 0 /** Compatibility with non-clang compilers. */ 32 | #endif 33 | 34 | #if __has_builtin(__builtin_expect) 35 | #define UNLIKELY(x) __builtin_expect(!!(x), 0) 36 | #define LIKELY(x) __builtin_expect(!!(x), 1) 37 | #else 38 | #define UNLIKELY(x) (x) 39 | #define LIKELY(x) (x) 40 | #endif 41 | 42 | #if __has_builtin(__builtin_memcpy) 43 | #define wasm_rt_memcpy __builtin_memcpy 44 | #else 45 | #define wasm_rt_memcpy memcpy 46 | #endif 47 | 48 | #if __has_builtin(__builtin_unreachable) 49 | #define wasm_rt_unreachable __builtin_unreachable 50 | #else 51 | #define wasm_rt_unreachable abort 52 | #endif 53 | 54 | #ifdef __STDC_VERSION__ 55 | #if __STDC_VERSION__ >= 201112L 56 | #define WASM_RT_C11_AVAILABLE 57 | #endif 58 | #endif 59 | 60 | /** 61 | * Many devices don't implement the C11 threads.h. We use CriticalSection APIs 62 | * for Windows and pthreads on other platforms where threads are not available. 63 | */ 64 | #ifdef WASM_RT_C11_AVAILABLE 65 | 66 | #if defined(_WIN32) 67 | #include 68 | #define WASM_RT_MUTEX CRITICAL_SECTION 69 | #define WASM_RT_USE_CRITICALSECTION 1 70 | #elif defined(__APPLE__) || defined(__STDC_NO_THREADS__) 71 | #include 72 | #define WASM_RT_MUTEX pthread_mutex_t 73 | #define WASM_RT_USE_PTHREADS 1 74 | #else 75 | #include 76 | #define WASM_RT_MUTEX mtx_t 77 | #define WASM_RT_USE_C11THREADS 1 78 | #endif 79 | 80 | #endif 81 | 82 | #ifdef _MSC_VER 83 | #define WASM_RT_THREAD_LOCAL __declspec(thread) 84 | #elif defined(WASM_RT_C11_AVAILABLE) 85 | #define WASM_RT_THREAD_LOCAL _Thread_local 86 | #else 87 | #define WASM_RT_THREAD_LOCAL 88 | #endif 89 | 90 | /** 91 | * If enabled, perform additional sanity checks in the generated wasm2c code and 92 | * wasm2c runtime. This is useful to enable on debug builds. 93 | */ 94 | #ifndef WASM_RT_SANITY_CHECKS 95 | #define WASM_RT_SANITY_CHECKS 0 96 | #endif 97 | 98 | /** 99 | * Backward compatibility: Convert the previously exposed 100 | * WASM_RT_MEMCHECK_SIGNAL_HANDLER macro to the ALLOCATION and CHECK macros that 101 | * are now used. 102 | */ 103 | #if defined(WASM_RT_MEMCHECK_SIGNAL_HANDLER) 104 | 105 | #if WASM_RT_MEMCHECK_SIGNAL_HANDLER 106 | #define WASM_RT_USE_MMAP 1 107 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 108 | #else 109 | #define WASM_RT_USE_MMAP 0 110 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 111 | #endif 112 | 113 | #warning \ 114 | "WASM_RT_MEMCHECK_SIGNAL_HANDLER has been deprecated in favor of WASM_RT_USE_MMAP and WASM_RT_MEMORY_CHECK_* macros" 115 | #endif 116 | 117 | /** 118 | * Specify if we use OR mmap/mprotect (+ Windows equivalents) OR malloc/realloc 119 | * for the Wasm memory allocation and growth. mmap/mprotect guarantees memory 120 | * will grow without being moved, while malloc ensures the virtual memory is 121 | * consumed only as needed, but may relocate the memory to handle memory 122 | * fragmentation. 123 | * 124 | * This defaults to malloc on 32-bit platforms or if memory64 support is needed. 125 | * It defaults to mmap on 64-bit platforms assuming memory64 support is not 126 | * needed (so we can use the guard based range checks below). 127 | */ 128 | #ifndef WASM_RT_USE_MMAP 129 | #if UINTPTR_MAX > 0xffffffff && !SUPPORT_MEMORY64 130 | #define WASM_RT_USE_MMAP 1 131 | #else 132 | #define WASM_RT_USE_MMAP 0 133 | #endif 134 | #endif 135 | 136 | /** 137 | * Set the range checking strategy for Wasm memories. 138 | * 139 | * GUARD_PAGES: memory accesses rely on unmapped pages/guard pages to trap 140 | * out-of-bound accesses. 141 | * 142 | * BOUNDS_CHECK: memory accesses are checked with explicit bounds checks. 143 | * 144 | * This defaults to GUARD_PAGES as this is the fasest option, iff the 145 | * requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy, 146 | * no 64-bit memories, no big-endian --- are met. This falls back to BOUNDS 147 | * otherwise. 148 | */ 149 | 150 | /** Check if Guard checks are supported */ 151 | #if UINTPTR_MAX > 0xffffffff && WASM_RT_USE_MMAP && !SUPPORT_MEMORY64 && \ 152 | !WABT_BIG_ENDIAN 153 | #define WASM_RT_GUARD_PAGES_SUPPORTED 1 154 | #else 155 | #define WASM_RT_GUARD_PAGES_SUPPORTED 0 156 | #endif 157 | 158 | /** Specify defaults for memory checks if unspecified */ 159 | #if !defined(WASM_RT_MEMCHECK_GUARD_PAGES) && \ 160 | !defined(WASM_RT_MEMCHECK_BOUNDS_CHECK) 161 | #if WASM_RT_GUARD_PAGES_SUPPORTED 162 | #define WASM_RT_MEMCHECK_GUARD_PAGES 1 163 | #else 164 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 165 | #endif 166 | #endif 167 | 168 | /** Ensure the macros are defined */ 169 | #ifndef WASM_RT_MEMCHECK_GUARD_PAGES 170 | #define WASM_RT_MEMCHECK_GUARD_PAGES 0 171 | #endif 172 | #ifndef WASM_RT_MEMCHECK_BOUNDS_CHECK 173 | #define WASM_RT_MEMCHECK_BOUNDS_CHECK 0 174 | #endif 175 | 176 | /** Sanity check the use of guard pages */ 177 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_GUARD_PAGES_SUPPORTED 178 | #error \ 179 | "WASM_RT_MEMCHECK_GUARD_PAGES not supported on this platform/configuration" 180 | #endif 181 | 182 | #if WASM_RT_MEMCHECK_GUARD_PAGES && WASM_RT_MEMCHECK_BOUNDS_CHECK 183 | #error \ 184 | "Cannot use both WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 185 | 186 | #elif !WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_MEMCHECK_BOUNDS_CHECK 187 | #error \ 188 | "Must choose at least one from WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" 189 | #endif 190 | 191 | /** 192 | * Some configurations above require the Wasm runtime to install a signal 193 | * handler. However, this can be explicitly disallowed by the host using 194 | * WASM_RT_SKIP_SIGNAL_RECOVERY. In this case, when the wasm code encounters an 195 | * OOB access, it may either trap or abort. 196 | */ 197 | #ifndef WASM_RT_SKIP_SIGNAL_RECOVERY 198 | #define WASM_RT_SKIP_SIGNAL_RECOVERY 0 199 | #endif 200 | 201 | #if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_SKIP_SIGNAL_RECOVERY 202 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 1 203 | #else 204 | #define WASM_RT_INSTALL_SIGNAL_HANDLER 0 205 | #endif 206 | 207 | /** 208 | * This macro, if defined to 1 (i.e., allows the "segue" optimization), allows 209 | * Wasm2c to use segment registers to speedup access to the linear heap. Note 210 | * that even if allowed in this way, the segment registers would only be used if 211 | * Wasm2c output is compiled for a suitable architecture and OS and the produces 212 | * C file is compiled by supported compilers. The extact restrictions are listed 213 | * in detail in src/template/wasm2c.declarations.c 214 | */ 215 | #ifndef WASM_RT_ALLOW_SEGUE 216 | #define WASM_RT_ALLOW_SEGUE 0 217 | #endif 218 | 219 | /** 220 | * The segue optimization restores x86 segments to their old values when exiting 221 | * wasm2c code. If WASM_RT_SEGUE_FREE_SEGMENT is defined, wasm2c assumes it has 222 | * exclusive use of the segment and optimizes performance in two ways. First, it 223 | * does not restore the "old" value of the segment during exits. Second, wasm2c 224 | * only sets the segment register if the value has changed since the last time 225 | * it was set. 226 | */ 227 | #ifndef WASM_RT_SEGUE_FREE_SEGMENT 228 | #define WASM_RT_SEGUE_FREE_SEGMENT 0 229 | #endif 230 | 231 | /** 232 | * This macro, if defined, allows the embedder to disable all stack exhaustion 233 | * checks. This a non conformant configuration, i.e., this does not respect 234 | * Wasm's specification, and may compromise security. Use with caution. 235 | */ 236 | #ifndef WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 237 | #define WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 0 238 | #endif 239 | 240 | /** 241 | * We need to detect and trap stack overflows. If we use a signal handler on 242 | * POSIX systems, this can detect call stack overflows. On windows, or platforms 243 | * without a signal handler, we use stack depth counting. 244 | */ 245 | #if !defined(WASM_RT_STACK_DEPTH_COUNT) && \ 246 | !defined(WASM_RT_STACK_EXHAUSTION_HANDLER) && \ 247 | !WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 248 | 249 | #if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) 250 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 1 251 | #else 252 | #define WASM_RT_STACK_DEPTH_COUNT 1 253 | #endif 254 | 255 | #endif 256 | 257 | /** Ensure the stack macros are defined */ 258 | #ifndef WASM_RT_STACK_DEPTH_COUNT 259 | #define WASM_RT_STACK_DEPTH_COUNT 0 260 | #endif 261 | #ifndef WASM_RT_STACK_EXHAUSTION_HANDLER 262 | #define WASM_RT_STACK_EXHAUSTION_HANDLER 0 263 | #endif 264 | 265 | #if WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 266 | 267 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) != 0 268 | #error \ 269 | "Cannot specify WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION along with WASM_RT_STACK_EXHAUSTION_HANDLER or WASM_RT_STACK_DEPTH_COUNT" 270 | #endif 271 | 272 | #else 273 | 274 | #if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) > 1 275 | #error \ 276 | "Cannot specify multiple options from WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 277 | #elif (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) == 0 278 | #error \ 279 | "Must specify one of WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" 280 | #endif 281 | 282 | #endif 283 | 284 | #if WASM_RT_STACK_EXHAUSTION_HANDLER && !WASM_RT_INSTALL_SIGNAL_HANDLER 285 | #error \ 286 | "WASM_RT_STACK_EXHAUSTION_HANDLER can only be used if WASM_RT_INSTALL_SIGNAL_HANDLER is enabled" 287 | #endif 288 | 289 | #if WASM_RT_STACK_DEPTH_COUNT 290 | /** 291 | * When the signal handler cannot be used to detect stack overflows, stack depth 292 | * is limited explicitly. The maximum stack depth before trapping can be 293 | * configured by defining this symbol before including wasm-rt when building the 294 | * generated c files, for example: 295 | * 296 | * ``` 297 | * cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o 298 | * ``` 299 | */ 300 | #ifndef WASM_RT_MAX_CALL_STACK_DEPTH 301 | #define WASM_RT_MAX_CALL_STACK_DEPTH 500 302 | #endif 303 | 304 | /** Current call stack depth. */ 305 | extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; 306 | 307 | #endif 308 | 309 | #if WASM_RT_USE_SEGUE || WASM_RT_ALLOW_SEGUE 310 | /** 311 | * The segue optimization uses x86 segments to point to a linear memory. If 312 | * used, the runtime must query whether it can use the fast userspace wrgsbase 313 | * instructions or whether it must invoke syscalls to set the segment base, 314 | * depending on the supported CPU features. The result of this query is saved in 315 | * this variable. 316 | */ 317 | extern bool wasm_rt_fsgsbase_inst_supported; 318 | /** 319 | * If fast userspace wrgsbase instructions don't exist, the runtime most provide 320 | * a function that invokes the OS' underlying syscall to set the segment base. 321 | */ 322 | void wasm_rt_syscall_set_segue_base(void* base); 323 | /** 324 | * If fast userspace rdgsbase instructions don't exist, the runtime most provide 325 | * a function that invokes the OS' underlying syscall to get the segment base. 326 | */ 327 | void* wasm_rt_syscall_get_segue_base(); 328 | /** 329 | * If WASM_RT_SEGUE_FREE_SEGMENT is defined, we must only set the segment 330 | * register if it was changed since the last time it was set. The last value set 331 | * on the segment register is stored in this variable. 332 | */ 333 | #if WASM_RT_SEGUE_FREE_SEGMENT 334 | extern WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val; 335 | #endif 336 | #endif 337 | 338 | #if defined(_MSC_VER) 339 | #define WASM_RT_NO_RETURN __declspec(noreturn) 340 | #else 341 | #define WASM_RT_NO_RETURN __attribute__((noreturn)) 342 | #endif 343 | 344 | #if defined(__APPLE__) && WASM_RT_STACK_EXHAUSTION_HANDLER 345 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1 346 | #else 347 | #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0 348 | #endif 349 | 350 | /** Reason a trap occurred. Provide this to `wasm_rt_trap`. */ 351 | typedef enum { 352 | WASM_RT_TRAP_NONE, /** No error. */ 353 | WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory or a table. */ 354 | WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */ 355 | WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */ 356 | WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */ 357 | WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */ 358 | WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */ 359 | WASM_RT_TRAP_UNCAUGHT_EXCEPTION, /** Exception thrown and not caught. */ 360 | WASM_RT_TRAP_UNALIGNED, /** Unaligned atomic instruction executed. */ 361 | #if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 362 | WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB, 363 | #else 364 | WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */ 365 | #endif 366 | } wasm_rt_trap_t; 367 | 368 | /** Value types. Used to define function signatures. */ 369 | typedef enum { 370 | WASM_RT_I32, 371 | WASM_RT_I64, 372 | WASM_RT_F32, 373 | WASM_RT_F64, 374 | WASM_RT_V128, 375 | WASM_RT_FUNCREF, 376 | WASM_RT_EXTERNREF, 377 | } wasm_rt_type_t; 378 | 379 | /** 380 | * A generic function pointer type, both for Wasm functions (`code`) 381 | * and host functions (`hostcode`). All function pointers are stored 382 | * in this canonical form, but must be cast to their proper signature 383 | * to call. 384 | */ 385 | typedef void (*wasm_rt_function_ptr_t)(void); 386 | 387 | /** 388 | * A pointer to a "tail-callee" function, called by a tail-call 389 | * trampoline or by another tail-callee function. (The definition uses a 390 | * single-member struct to allow a recursive definition.) 391 | */ 392 | typedef struct wasm_rt_tailcallee_t { 393 | void (*fn)(void** instance_ptr, 394 | void* tail_call_stack, 395 | struct wasm_rt_tailcallee_t* next); 396 | } wasm_rt_tailcallee_t; 397 | 398 | /** 399 | * The type of a function (an arbitrary number of param and result types). 400 | * This is represented as an opaque 256-bit ID. 401 | */ 402 | typedef const char* wasm_rt_func_type_t; 403 | 404 | /** 405 | * A function instance (the runtime representation of a function). 406 | * These can be stored in tables of type funcref, or used as values. 407 | */ 408 | typedef struct { 409 | /** The function's type. */ 410 | wasm_rt_func_type_t func_type; 411 | /** 412 | * The function. The embedder must know the actual C signature of the function 413 | * and cast to it before calling. 414 | */ 415 | wasm_rt_function_ptr_t func; 416 | /** An alternate version of the function to be used when tail-called. */ 417 | wasm_rt_tailcallee_t func_tailcallee; 418 | /** 419 | * A function instance is a closure of the function over an instance 420 | * of the originating module. The module_instance element will be passed into 421 | * the function at runtime. 422 | */ 423 | void* module_instance; 424 | } wasm_rt_funcref_t; 425 | 426 | /** Default (null) value of a funcref */ 427 | #define wasm_rt_funcref_null_value \ 428 | ((wasm_rt_funcref_t){NULL, NULL, {NULL}, NULL}) 429 | 430 | /** The type of an external reference (opaque to WebAssembly). */ 431 | typedef void* wasm_rt_externref_t; 432 | 433 | /** Default (null) value of an externref */ 434 | #define wasm_rt_externref_null_value ((wasm_rt_externref_t){NULL}) 435 | 436 | /** A Memory object. */ 437 | typedef struct { 438 | /** The linear memory data, with a byte length of `size`. */ 439 | uint8_t* data; 440 | /** The current page count for this Memory object. */ 441 | uint64_t pages; 442 | /** 443 | * The maximum page count for this Memory object. If there is no maximum, 444 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 445 | */ 446 | uint64_t max_pages; 447 | /** The current size of the linear memory, in bytes. */ 448 | uint64_t size; 449 | /** Is this memory indexed by u64 (as opposed to default u32) */ 450 | bool is64; 451 | } wasm_rt_memory_t; 452 | 453 | #ifdef WASM_RT_C11_AVAILABLE 454 | /** A shared Memory object. */ 455 | typedef struct { 456 | /** 457 | * The linear memory data, with a byte length of `size`. The memory is marked 458 | * atomic as it is shared and may have to be accessed with different memory 459 | * orders --- sequential when being accessed atomically, relaxed otherwise. 460 | * Unfortunately, the C standard does not state what happens if there are 461 | * overlaps in two memory accesses which have a memory order, e.g., an 462 | * atomic32 being read from the same location an atomic64 is read. One way to 463 | * prevent optimizations from assuming non-overlapping behavior as typically 464 | * done in C is to mark the memory as volatile. Thus the memory is atomic and 465 | * volatile. 466 | */ 467 | _Atomic volatile uint8_t* data; 468 | /** The current page count for this Memory object. */ 469 | uint64_t pages; 470 | /** 471 | * The maximum page count for this Memory object. If there is no maximum, 472 | * `max_pages` is 0xffffffffu (i.e. UINT32_MAX). 473 | */ 474 | uint64_t max_pages; 475 | /** The current size of the linear memory, in bytes. */ 476 | uint64_t size; 477 | /** Is this memory indexed by u64 (as opposed to default u32) */ 478 | bool is64; 479 | /** Lock used to ensure operations such as memory grow are threadsafe */ 480 | WASM_RT_MUTEX mem_lock; 481 | } wasm_rt_shared_memory_t; 482 | #endif 483 | 484 | /** A Table of type funcref. */ 485 | typedef struct { 486 | /** The table element data, with an element count of `size`. */ 487 | wasm_rt_funcref_t* data; 488 | /** 489 | * The maximum element count of this Table object. If there is no maximum, 490 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 491 | */ 492 | uint32_t max_size; 493 | /** The current element count of the table. */ 494 | uint32_t size; 495 | } wasm_rt_funcref_table_t; 496 | 497 | /** A Table of type externref. */ 498 | typedef struct { 499 | /** The table element data, with an element count of `size`. */ 500 | wasm_rt_externref_t* data; 501 | /** 502 | * The maximum element count of this Table object. If there is no maximum, 503 | * `max_size` is 0xffffffffu (i.e. UINT32_MAX). 504 | */ 505 | uint32_t max_size; 506 | /** The current element count of the table. */ 507 | uint32_t size; 508 | } wasm_rt_externref_table_t; 509 | 510 | /** Initialize the runtime. */ 511 | void wasm_rt_init(void); 512 | 513 | /** Is the runtime initialized? */ 514 | bool wasm_rt_is_initialized(void); 515 | 516 | /** Free the runtime's state. */ 517 | void wasm_rt_free(void); 518 | 519 | /* 520 | * Initialize the multithreaded runtime for a given thread. Must be 521 | * called by each thread (other than the one that called wasm_rt_init) 522 | * before initializing a Wasm module or calling an exported 523 | * function. 524 | */ 525 | void wasm_rt_init_thread(void); 526 | 527 | /* 528 | * Free the individual thread's state. 529 | */ 530 | void wasm_rt_free_thread(void); 531 | 532 | /** A hardened jmp_buf that allows checking for initialization before use */ 533 | typedef struct { 534 | /** Is the jmp buf intialized? */ 535 | bool initialized; 536 | /** jmp_buf contents */ 537 | jmp_buf buffer; 538 | } wasm_rt_jmp_buf; 539 | 540 | #ifndef _WIN32 541 | #define WASM_RT_SETJMP_SETBUF(buf) sigsetjmp(buf, 1) 542 | #else 543 | #define WASM_RT_SETJMP_SETBUF(buf) setjmp(buf) 544 | #endif 545 | 546 | #define WASM_RT_SETJMP(buf) \ 547 | ((buf).initialized = true, WASM_RT_SETJMP_SETBUF((buf).buffer)) 548 | 549 | #ifndef _WIN32 550 | #define WASM_RT_LONGJMP_UNCHECKED(buf, val) siglongjmp(buf, val) 551 | #else 552 | #define WASM_RT_LONGJMP_UNCHECKED(buf, val) longjmp(buf, val) 553 | #endif 554 | 555 | #define WASM_RT_LONGJMP(buf, val) \ 556 | /** Abort on failure as this may be called in the trap handler */ \ 557 | if (!((buf).initialized)) \ 558 | abort(); \ 559 | (buf).initialized = false; \ 560 | WASM_RT_LONGJMP_UNCHECKED((buf).buffer, val) 561 | 562 | /** 563 | * Stop execution immediately and jump back to the call to `wasm_rt_impl_try`. 564 | * The result of `wasm_rt_impl_try` will be the provided trap reason. 565 | * 566 | * This is typically called by the generated code, and not the embedder. 567 | */ 568 | WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t); 569 | 570 | /** Return a human readable error string based on a trap type. */ 571 | const char* wasm_rt_strerror(wasm_rt_trap_t trap); 572 | 573 | #define wasm_rt_try(target) WASM_RT_SETJMP(target) 574 | 575 | /** 576 | * Initialize a Memory object with an initial page size of `initial_pages` and 577 | * a maximum page size of `max_pages`, indexed with an i32 or i64. 578 | * 579 | * ``` 580 | * wasm_rt_memory_t my_memory; 581 | * // 1 initial page (65536 bytes), and a maximum of 2 pages, 582 | * // indexed with an i32 583 | * wasm_rt_allocate_memory(&my_memory, 1, 2, false); 584 | * ``` 585 | */ 586 | void wasm_rt_allocate_memory(wasm_rt_memory_t*, 587 | uint64_t initial_pages, 588 | uint64_t max_pages, 589 | bool is64); 590 | 591 | /** 592 | * Grow a Memory object by `pages`, and return the previous page count. If 593 | * this new page count is greater than the maximum page count, the grow fails 594 | * and 0xffffffffu (UINT32_MAX) is returned instead. 595 | * 596 | * ``` 597 | * wasm_rt_memory_t my_memory; 598 | * ... 599 | * // Grow memory by 10 pages. 600 | * uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10); 601 | * if (old_page_size == UINT32_MAX) { 602 | * // Failed to grow memory. 603 | * } 604 | * ``` 605 | */ 606 | uint64_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint64_t pages); 607 | 608 | /** Free a Memory object. */ 609 | void wasm_rt_free_memory(wasm_rt_memory_t*); 610 | 611 | #ifdef WASM_RT_C11_AVAILABLE 612 | /** Shared memory version of wasm_rt_allocate_memory */ 613 | void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, 614 | uint64_t initial_pages, 615 | uint64_t max_pages, 616 | bool is64); 617 | 618 | /** Shared memory version of wasm_rt_grow_memory */ 619 | uint64_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint64_t pages); 620 | 621 | /** Shared memory version of wasm_rt_free_memory */ 622 | void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*); 623 | #endif 624 | 625 | /** 626 | * Initialize a funcref Table object with an element count of `elements` and a 627 | * maximum size of `max_elements`. 628 | * 629 | * ``` 630 | * wasm_rt_funcref_table_t my_table; 631 | * // 5 elements and a maximum of 10 elements. 632 | * wasm_rt_allocate_funcref_table(&my_table, 5, 10); 633 | * ``` 634 | */ 635 | void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t*, 636 | uint32_t elements, 637 | uint32_t max_elements); 638 | 639 | /** Free a funcref Table object. */ 640 | void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t*); 641 | 642 | /** 643 | * Initialize an externref Table object with an element count 644 | * of `elements` and a maximum size of `max_elements`. 645 | * Usage as per wasm_rt_allocate_funcref_table. 646 | */ 647 | void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*, 648 | uint32_t elements, 649 | uint32_t max_elements); 650 | 651 | /** Free an externref Table object. */ 652 | void wasm_rt_free_externref_table(wasm_rt_externref_table_t*); 653 | 654 | /** 655 | * Grow a Table object by `delta` elements (giving the new elements the value 656 | * `init`), and return the previous element count. If this new element count is 657 | * greater than the maximum element count, the grow fails and 0xffffffffu 658 | * (UINT32_MAX) is returned instead. 659 | */ 660 | uint32_t wasm_rt_grow_funcref_table(wasm_rt_funcref_table_t*, 661 | uint32_t delta, 662 | wasm_rt_funcref_t init); 663 | uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t*, 664 | uint32_t delta, 665 | wasm_rt_externref_t init); 666 | 667 | #ifdef __cplusplus 668 | } 669 | #endif 670 | 671 | #endif /* WASM_RT_H_ */ -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | apply(from: { 3 | def searchDir = rootDir.toPath() 4 | do { 5 | def p = searchDir.resolve("node_modules/react-native-test-app/android/dependencies.gradle") 6 | if (p.toFile().exists()) { 7 | return p.toRealPath().toString() 8 | } 9 | } while (searchDir = searchDir.getParent()) 10 | throw new GradleException("Could not find `react-native-test-app`"); 11 | }()) 12 | 13 | repositories { 14 | mavenCentral() 15 | google() 16 | } 17 | 18 | dependencies { 19 | getReactNativeDependencies().each { dependency -> 20 | classpath(dependency) 21 | } 22 | } 23 | } 24 | 25 | allprojects { 26 | repositories { 27 | maven { 28 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 29 | url({ 30 | def searchDir = rootDir.toPath() 31 | do { 32 | def p = searchDir.resolve("node_modules/react-native/android") 33 | if (p.toFile().exists()) { 34 | return p.toRealPath().toString() 35 | } 36 | } while (searchDir = searchDir.getParent()) 37 | throw new GradleException("Could not find `react-native`"); 38 | }()) 39 | } 40 | mavenCentral() 41 | google() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /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 Gradle Daemon. The setting is 11 | # particularly useful for configuring JVM memory settings for build performance. 12 | # This does not affect the JVM settings for the Gradle client VM. 13 | # The default is `-Xmx512m -XX:MaxMetaspaceSize=256m`. 14 | org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 15 | 16 | # When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute 17 | # projects in parallel. To learn more about parallel task execution, see the 18 | # section on Gradle build performance: 19 | # https://docs.gradle.org/current/userguide/performance.html#parallel_execution. 20 | # Default is `false`. 21 | #org.gradle.parallel=true 22 | 23 | # AndroidX package structure to make it clearer which packages are bundled with the 24 | # Android operating system, and which are packaged with your app's APK 25 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 26 | android.useAndroidX=true 27 | # Automatically convert third-party libraries to use AndroidX 28 | android.enableJetifier=false 29 | # Jetifier randomly fails on these libraries 30 | android.jetifier.ignorelist=hermes-android,react-android 31 | 32 | # Use this property to specify which architecture you want to build. 33 | # You can also override it from the CLI using 34 | # ./gradlew -PreactNativeArchitectures=x86_64 35 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 36 | 37 | # Use this property to enable support to the new architecture. 38 | # This will allow you to use TurboModules and the Fabric render in 39 | # your application. You should enable this flag either if you want 40 | # to write custom TurboModules/Fabric components OR use libraries that 41 | # are providing them. 42 | # Note that this is incompatible with web debugging. 43 | #newArchEnabled=true 44 | #bridgelessEnabled=true 45 | 46 | # Uncomment the line below to build React Native from source. 47 | #react.buildFromSource=true 48 | 49 | # Version of Android NDK to build against. 50 | #ANDROID_NDK_VERSION=26.1.10909125 51 | 52 | # Version of Kotlin to build against. 53 | #KOTLIN_VERSION=1.8.22 54 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callstack/react-native-rapier/533182886223aea1d773d01877671edf8c09c644/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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/HEAD/platforms/jvm/plugins-application/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 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | 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 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /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 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | google() 6 | } 7 | } 8 | 9 | rootProject.name = "ReactNativeRapierExample" 10 | 11 | apply(from: { 12 | def searchDir = rootDir.toPath() 13 | do { 14 | def p = searchDir.resolve("node_modules/react-native-test-app/test-app.gradle") 15 | if (p.toFile().exists()) { 16 | return p.toRealPath().toString() 17 | } 18 | } while (searchDir = searchDir.getParent()) 19 | throw new GradleException("Could not find `react-native-test-app`"); 20 | }()) 21 | applyTestAppSettings(settings) 22 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactNativeRapierExample", 3 | "displayName": "ReactNativeRapierExample", 4 | "components": [ 5 | { 6 | "appKey": "ReactNativeRapierExample", 7 | "displayName": "ReactNativeRapierExample" 8 | } 9 | ], 10 | "resources": { 11 | "android": [ 12 | "dist/res", 13 | "dist/main.android.jsbundle" 14 | ], 15 | "ios": [ 16 | "dist/assets", 17 | "dist/main.ios.jsbundle" 18 | ], 19 | "macos": [ 20 | "dist/assets", 21 | "dist/main.macos.jsbundle" 22 | ], 23 | "visionos": [ 24 | "dist/assets", 25 | "dist/main.visionos.jsbundle" 26 | ], 27 | "windows": [ 28 | "dist/assets", 29 | "dist/main.windows.bundle" 30 | ] 31 | }, 32 | "android": { 33 | "package": "callstack.reactnativerapier.example" 34 | }, 35 | "ios": { 36 | "bundleIdentifier": "callstack.reactnativerapier.example" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { getConfig } = require('react-native-builder-bob/babel-config'); 3 | const pkg = require('../package.json'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | 7 | module.exports = getConfig( 8 | { 9 | presets: ['module:@react-native/babel-preset'], 10 | }, 11 | { root, pkg } 12 | ); 13 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /example/ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // ReactNativeRapierExample 4 | // 5 | 6 | import Foundation 7 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | ws_dir = Pathname.new(__dir__) 2 | ws_dir = ws_dir.parent until 3 | File.exist?("#{ws_dir}/node_modules/react-native-test-app/test_app.rb") || 4 | ws_dir.expand_path.to_s == '/' 5 | require "#{ws_dir}/node_modules/react-native-test-app/test_app.rb" 6 | 7 | workspace 'ReactNativeRapierExample.xcworkspace' 8 | 9 | options = { 10 | :fabric_enabled => true, 11 | :bridgeless_enabled => true, 12 | } 13 | 14 | use_test_app! options 15 | -------------------------------------------------------------------------------- /example/ios/ReactNativeRapierExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /example/ios/ReactNativeRapierExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { getDefaultConfig } = require('@react-native/metro-config'); 3 | const { getConfig } = require('react-native-builder-bob/metro-config'); 4 | const pkg = require('../package.json'); 5 | 6 | const root = path.resolve(__dirname, '..'); 7 | 8 | /** 9 | * Metro configuration 10 | * https://facebook.github.io/metro/docs/configuration 11 | * 12 | * @type {import('metro-config').MetroConfig} 13 | */ 14 | module.exports = getConfig(getDefaultConfig(__dirname), { 15 | root, 16 | pkg, 17 | project: __dirname, 18 | }); 19 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@callstack/react-native-rapier-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "build:android": "npm run mkdist && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist && react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"", 8 | "build:ios": "npm run mkdist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist && react-native build-ios --scheme ReactNativeRapierExample --mode Debug --extra-params \"-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO\"", 9 | "ios": "react-native run-ios", 10 | "mkdist": "node -e \"require('node:fs').mkdirSync('dist', { recursive: true, mode: 0o755 })\"", 11 | "start": "react-native start" 12 | }, 13 | "dependencies": { 14 | "react": "18.3.1", 15 | "react-native": "0.75.4" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.20.0", 19 | "@babel/preset-env": "^7.20.0", 20 | "@babel/runtime": "^7.20.0", 21 | "@react-native/babel-preset": "0.75.4", 22 | "@react-native/metro-config": "0.75.4", 23 | "@react-native/typescript-config": "0.75.4", 24 | "@rnx-kit/metro-config": "^2.0.0", 25 | "react-native-builder-bob": "^0.30.2", 26 | "react-native-test-app": "^3.10.14" 27 | }, 28 | "engines": { 29 | "node": ">=18" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pkg = require('../package.json'); 3 | const { configureProjects } = require('react-native-test-app'); 4 | 5 | module.exports = { 6 | project: configureProjects({ 7 | android: { 8 | sourceDir: 'android', 9 | }, 10 | ios: { 11 | sourceDir: 'ios', 12 | automaticPodsInstallation: true, 13 | }, 14 | }), 15 | dependencies: { 16 | [pkg.name]: { 17 | root: path.join(__dirname, '..'), 18 | }, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from 'react'; 2 | import { StyleSheet, View, Text, Button } from 'react-native'; 3 | import Rapier from '@callstack/react-native-rapier'; 4 | 5 | export default function App() { 6 | const [module, setModule] = useState(); 7 | 8 | useEffect(() => { 9 | setModule(Rapier.create({ wbg: {} })); 10 | }, []); 11 | 12 | const callFn = useCallback(() => { 13 | console.log(module, module.exports); 14 | let res = module.exports.rawimpulsejointset_new(); 15 | console.log('res: ', res); 16 | }, [module]); 17 | 18 | return ( 19 | 20 | Module loaded: {!!module} 21 | {!!module && {JSON.stringify(module)}} 22 | {!!module &&