diff --git a/change/@office-iss-react-native-win32-3e9a2f0b-e14e-4de2-bae8-fe92b29112dd.json b/change/@office-iss-react-native-win32-3e9a2f0b-e14e-4de2-bae8-fe92b29112dd.json
new file mode 100644
index 00000000000..d05cfc2980c
--- /dev/null
+++ b/change/@office-iss-react-native-win32-3e9a2f0b-e14e-4de2-bae8-fe92b29112dd.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "integrates 2/27/22",
+ "packageName": "@office-iss/react-native-win32",
+ "email": "email not defined",
+ "dependentChangeType": "patch"
+}
diff --git a/change/@react-native-windows-automation-channel-7a87de4b-82ba-412b-a105-ef96dda7437a.json b/change/@react-native-windows-automation-channel-7a87de4b-82ba-412b-a105-ef96dda7437a.json
new file mode 100644
index 00000000000..dca2745cb4d
--- /dev/null
+++ b/change/@react-native-windows-automation-channel-7a87de4b-82ba-412b-a105-ef96dda7437a.json
@@ -0,0 +1,7 @@
+{
+ "type": "patch",
+ "comment": "integrates 2/27/22",
+ "packageName": "@react-native-windows/automation-channel",
+ "email": "email not defined",
+ "dependentChangeType": "patch"
+}
diff --git a/change/@react-native-windows-virtualized-list-ba05714e-8a5f-4e00-8a69-28e147d800fa.json b/change/@react-native-windows-virtualized-list-ba05714e-8a5f-4e00-8a69-28e147d800fa.json
new file mode 100644
index 00000000000..1856eeee316
--- /dev/null
+++ b/change/@react-native-windows-virtualized-list-ba05714e-8a5f-4e00-8a69-28e147d800fa.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "integrates 2/27/22",
+ "packageName": "@react-native-windows/virtualized-list",
+ "email": "email not defined",
+ "dependentChangeType": "patch"
+}
diff --git a/change/react-native-windows-57a34396-bb10-414e-8bd6-f08fcb1f6cef.json b/change/react-native-windows-57a34396-bb10-414e-8bd6-f08fcb1f6cef.json
new file mode 100644
index 00000000000..e6e36f96970
--- /dev/null
+++ b/change/react-native-windows-57a34396-bb10-414e-8bd6-f08fcb1f6cef.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "integrates 2/27/22",
+ "packageName": "react-native-windows",
+ "email": "email not defined",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/@office-iss/react-native-win32-tester/overrides.json b/packages/@office-iss/react-native-win32-tester/overrides.json
index 10b0f8885ad..1f1c8b13224 100644
--- a/packages/@office-iss/react-native-win32-tester/overrides.json
+++ b/packages/@office-iss/react-native-win32-tester/overrides.json
@@ -5,7 +5,7 @@
"excludePatterns": [
"src/js/examples-win32/**"
],
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "patch",
diff --git a/packages/@office-iss/react-native-win32-tester/package.json b/packages/@office-iss/react-native-win32-tester/package.json
index 9bb3281b896..4a3ecd069e2 100644
--- a/packages/@office-iss/react-native-win32-tester/package.json
+++ b/packages/@office-iss/react-native-win32-tester/package.json
@@ -16,7 +16,7 @@
"peerDependencies": {
"@office-iss/react-native-win32": "^0.0.0-canary.137",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423"
+ "react-native": "0.0.0-20220227-2009-189c2c895"
},
"devDependencies": {
"@office-iss/react-native-win32": "^0.0.0-canary.137",
@@ -26,7 +26,7 @@
"@types/node": "^14.14.22",
"eslint": "^7.32.0",
"just-scripts": "^1.3.3",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-platform-override": "^1.6.6",
"typescript": "^4.4.4"
},
diff --git a/packages/@office-iss/react-native-win32/.flowconfig b/packages/@office-iss/react-native-win32/.flowconfig
index 552b6745d80..950b5bd698f 100644
--- a/packages/@office-iss/react-native-win32/.flowconfig
+++ b/packages/@office-iss/react-native-win32/.flowconfig
@@ -58,6 +58,8 @@
; Ignore files with flow typing issues #9223
.*/react-native-win32/Libraries/Core/ReactNativeVersionCheck.js
+.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
+
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
; Should work out how to do this properly
diff --git a/packages/@office-iss/react-native-win32/overrides.json b/packages/@office-iss/react-native-win32/overrides.json
index 0811d949474..a70d4c1aa35 100644
--- a/packages/@office-iss/react-native-win32/overrides.json
+++ b/packages/@office-iss/react-native-win32/overrides.json
@@ -7,19 +7,19 @@
"**/__snapshots__/**",
"src/rntypes/**"
],
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "derived",
"file": ".flowconfig",
"baseFile": ".flowconfig",
- "baseHash": "e0fd826d1c731209ca1f4322e950df83877ea95a"
+ "baseHash": "62cbbd198b5f952592fcffae5e5f88a387a2f190"
},
{
"type": "derived",
"file": "src/index.win32.js",
"baseFile": "index.js",
- "baseHash": "a33f356abc2db3767c8fee7e4d6bda60384787a1"
+ "baseHash": "2a0bd511c691be2ac3da45a3c77250aaf55414e1"
},
{
"type": "patch",
@@ -100,13 +100,6 @@
"baseFile": "Libraries/Components/SafeAreaView/SafeAreaView.js",
"baseHash": "d13d67c91a9096989776ba7d7b0f8537c46b87a8"
},
- {
- "type": "copy",
- "file": "src/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.js",
- "baseFile": "Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js",
- "baseHash": "a7b7561ee80510fb3a45bad5ad18bc9076152144",
- "issue": 4378
- },
{
"type": "platform",
"file": "src/Libraries/Components/Text/Tests/TextWin32Test.tsx"
@@ -131,7 +124,7 @@
"type": "derived",
"file": "src/Libraries/Components/TextInput/TextInput.win32.tsx",
"baseFile": "Libraries/Components/TextInput/TextInput.js",
- "baseHash": "c447994d5ac59824f298cf4aec899c174b78e3e2"
+ "baseHash": "567ebad070a2fb9020ef177ee30defba9f0c54ec"
},
{
"type": "patch",
@@ -443,7 +436,7 @@
"type": "patch",
"file": "src/Libraries/Types/CoreEventTypes.win32.js",
"baseFile": "Libraries/Types/CoreEventTypes.js",
- "baseHash": "b7ed94c49c38a6b3579349e6940bb663328c1f4e",
+ "baseHash": "12d577ba5b522593fb49d4621d5ad4bba0d37119",
"issue": 6240
},
{
diff --git a/packages/@office-iss/react-native-win32/package.json b/packages/@office-iss/react-native-win32/package.json
index a8798a4b8e3..a5013ce3cd3 100644
--- a/packages/@office-iss/react-native-win32/package.json
+++ b/packages/@office-iss/react-native-win32/package.json
@@ -22,7 +22,7 @@
"dependencies": {
"@babel/runtime": "^7.0.0",
"@jest/create-cache-key-function": "^27.0.1",
- "@react-native-community/cli": "^7.0.1",
+ "@react-native-community/cli": "^7.0.3",
"@react-native-community/cli-platform-android": "^7.0.1",
"@react-native-community/cli-platform-ios": "^7.0.1",
"@react-native-windows/virtualized-list": "0.0.0-canary.31",
@@ -37,16 +37,16 @@
"hermes-engine": "~0.11.0",
"invariant": "^2.2.4",
"jsc-android": "^250230.2.1",
- "metro-react-native-babel-transformer": "0.67.0",
- "metro-runtime": "0.67.0",
- "metro-source-map": "0.67.0",
+ "metro-react-native-babel-transformer": "0.68.0",
+ "metro-runtime": "0.68.0",
+ "metro-source-map": "0.68.0",
"nullthrows": "^1.1.1",
"pretty-format": "^26.5.2",
"promise": "^8.0.3",
"react-clone-referenced-element": "^1.0.1",
"react-devtools-core": "^4.23.0",
"react-native-codegen": "^0.0.13",
- "react-native-gradle-plugin": "^0.0.4",
+ "react-native-gradle-plugin": "^0.0.5",
"react-refresh": "^0.4.0",
"react-shallow-renderer": "16.14.1",
"regenerator-runtime": "^0.13.2",
@@ -72,14 +72,14 @@
"just-scripts": "^1.3.3",
"prettier": "^2.4.1",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-platform-override": "^1.6.6",
"react-shallow-renderer": "16.14.1",
"typescript": "^4.4.4"
},
"peerDependencies": {
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423"
+ "react-native": "0.0.0-20220227-2009-189c2c895"
},
"beachball": {
"defaultNpmTag": "canary",
diff --git a/packages/@office-iss/react-native-win32/src/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.js b/packages/@office-iss/react-native-win32/src/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.js
deleted file mode 100644
index afc2f621e78..00000000000
--- a/packages/@office-iss/react-native-win32/src/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-import * as React from 'react';
-import StyleSheet from '../../StyleSheet/StyleSheet';
-import Text from '../../Text/Text';
-import View from '../View/View';
-
-class DummySegmentedControlIOS extends React.Component {
- render() {
- return (
-
-
- SegmentedControlIOS is not supported on this platform!
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- dummy: {
- width: 120,
- height: 50,
- backgroundColor: '#ffbcbc',
- borderWidth: 1,
- borderColor: 'red',
- alignItems: 'center',
- justifyContent: 'center',
- },
- text: {
- color: '#333333',
- margin: 5,
- fontSize: 10,
- },
-});
-
-module.exports = DummySegmentedControlIOS;
diff --git a/packages/@office-iss/react-native-win32/src/Libraries/Types/CoreEventTypes.win32.js b/packages/@office-iss/react-native-win32/src/Libraries/Types/CoreEventTypes.win32.js
index 5148f07d48d..2e81584d819 100644
--- a/packages/@office-iss/react-native-win32/src/Libraries/Types/CoreEventTypes.win32.js
+++ b/packages/@office-iss/react-native-win32/src/Libraries/Types/CoreEventTypes.win32.js
@@ -11,7 +11,7 @@
import * as React from 'react';
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
-export type SyntheticEvent = $ReadOnly<{|
+export type SyntheticEvent<+T> = $ReadOnly<{|
bubbles: ?boolean,
cancelable: ?boolean,
currentTarget: number | React.ElementRef>,
diff --git a/packages/@office-iss/react-native-win32/src/index.win32.js b/packages/@office-iss/react-native-win32/src/index.win32.js
index b1516f8668b..9f629d94ea3 100644
--- a/packages/@office-iss/react-native-win32/src/index.win32.js
+++ b/packages/@office-iss/react-native-win32/src/index.win32.js
@@ -30,7 +30,6 @@ import typeof RefreshControl from './Libraries/Components/RefreshControl/Refresh
import typeof SafeAreaView from './Libraries/Components/SafeAreaView/SafeAreaView';
import typeof ScrollView from './Libraries/Components/ScrollView/ScrollView';
import typeof SectionList from './Libraries/Lists/SectionList';
-import typeof SegmentedControlIOS from './Libraries/Components/SegmentedControlIOS/SegmentedControlIOS';
import typeof Slider from './Libraries/Components/Slider/Slider';
import typeof StatusBar from './Libraries/Components/StatusBar/StatusBar';
import typeof Switch from './Libraries/Components/Switch/Switch';
@@ -197,16 +196,6 @@ module.exports = {
get SectionList(): SectionList {
return require('./Libraries/Lists/SectionList').default;
},
- // $FlowFixMe[value-as-type]
- get SegmentedControlIOS(): SegmentedControlIOS {
- warnOnce(
- 'segmented-control-ios-moved',
- 'SegmentedControlIOS has been extracted from react-native core and will be removed in a future release. ' +
- "It can now be installed and imported from '@react-native-segmented-control/segmented-control' instead of 'react-native'. " +
- 'See https://github.com/react-native-segmented-control/segmented-control',
- );
- return require('./Libraries/Components/SegmentedControlIOS/SegmentedControlIOS');
- },
get Slider(): Slider {
warnOnce(
'slider-moved',
@@ -685,8 +674,8 @@ if (__DEV__) {
invariant(
false,
'ViewPagerAndroid has been removed from React Native. ' +
- "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " +
- 'See https://github.com/callstack/react-native-viewpager',
+ "It can now be installed and imported from 'react-native-pager-view' instead of 'react-native'. " +
+ 'See https://github.com/callstack/react-native-pager-view',
);
},
});
@@ -707,6 +696,22 @@ if (__DEV__) {
},
});
+ /* $FlowFixMe[prop-missing] This is intentional: Flow will error when
+ * attempting to access SegmentedControlIOS. */
+ /* $FlowFixMe[invalid-export] This is intentional: Flow will error when
+ * attempting to access SegmentedControlIOS. */
+ Object.defineProperty(module.exports, 'SegmentedControlIOS', {
+ configurable: true,
+ get() {
+ invariant(
+ false,
+ 'SegmentedControlIOS has been removed from React Native. ' +
+ "It can now be installed and imported from '@react-native-community/segmented-checkbox' instead of 'react-native'." +
+ 'See https://github.com/react-native-segmented-control/segmented-control',
+ );
+ },
+ });
+
/* $FlowFixMe[prop-missing] This is intentional: Flow will error when
* attempting to access StatusBarIOS. */
/* $FlowFixMe[invalid-export] This is intentional: Flow will error when
diff --git a/packages/@react-native-windows/automation-channel/package.json b/packages/@react-native-windows/automation-channel/package.json
index 38d2a5bd724..266e68ef427 100644
--- a/packages/@react-native-windows/automation-channel/package.json
+++ b/packages/@react-native-windows/automation-channel/package.json
@@ -29,7 +29,7 @@
"just-scripts": "^1.3.2",
"prettier": "^2.4.1",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470",
"typescript": "^4.4.4"
},
@@ -40,4 +40,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/packages/@react-native-windows/tester/overrides.json b/packages/@react-native-windows/tester/overrides.json
index 3eee8dd4d95..c7e28099f7f 100644
--- a/packages/@react-native-windows/tester/overrides.json
+++ b/packages/@react-native-windows/tester/overrides.json
@@ -5,7 +5,7 @@
"excludePatterns": [
"src/js/examples-win/**"
],
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "patch",
diff --git a/packages/@react-native-windows/tester/package.json b/packages/@react-native-windows/tester/package.json
index ae2c5a93f43..658c14bec39 100644
--- a/packages/@react-native-windows/tester/package.json
+++ b/packages/@react-native-windows/tester/package.json
@@ -16,7 +16,7 @@
"peerDependencies": {
"@react-native-picker/picker": "2.2.0",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470",
"react-native-xaml": "^0.0.50"
},
@@ -27,7 +27,7 @@
"@types/node": "^14.14.22",
"eslint": "^7.32.0",
"just-scripts": "^1.3.3",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-platform-override": "^1.6.6",
"react-native-windows": "^0.0.0-canary.470",
"typescript": "^4.4.4"
@@ -35,4 +35,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/packages/@react-native-windows/virtualized-list/.flowconfig b/packages/@react-native-windows/virtualized-list/.flowconfig
index b5d4d52c6e4..dc7a1bc3972 100644
--- a/packages/@react-native-windows/virtualized-list/.flowconfig
+++ b/packages/@react-native-windows/virtualized-list/.flowconfig
@@ -5,6 +5,23 @@
.*/node_modules/react-native-windows/Microsoft.ReactNative.Managed.CodeGen.UnitTests/.*
.*/node_modules/react-native-windows/Microsoft.ReactNative.Managed.UnitTests/.*
+; Ignore templates for 'react-native init'
+/template/.*
+
+; Ignore the Dangerfile
+/bots/dangerfile.js
+
+; Ignore "BUCK" generated dirs
+/\.buckd/
+
+; Flow doesn't support platforms
+.*/Libraries/Utilities/LoadingView.js
+
+.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
+
+[untyped]
+.*/node_modules/@react-native-community/cli/.*/.*
+
[libs]
../../../node_modules/react-native/interface.js
../../../node_modules/react-native/flow/
diff --git a/packages/@react-native-windows/virtualized-list/overrides.json b/packages/@react-native-windows/virtualized-list/overrides.json
index d83872a1779..8b963477a68 100644
--- a/packages/@react-native-windows/virtualized-list/overrides.json
+++ b/packages/@react-native-windows/virtualized-list/overrides.json
@@ -3,13 +3,13 @@
".flowconfig",
"src/**"
],
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "derived",
"file": ".flowconfig",
"baseFile": ".flowconfig",
- "baseHash": "e0fd826d1c731209ca1f4322e950df83877ea95a"
+ "baseHash": "62cbbd198b5f952592fcffae5e5f88a387a2f190"
},
{
"type": "copy",
diff --git a/packages/@react-native-windows/virtualized-list/package.json b/packages/@react-native-windows/virtualized-list/package.json
index a7b73cd1035..47593fdc453 100644
--- a/packages/@react-native-windows/virtualized-list/package.json
+++ b/packages/@react-native-windows/virtualized-list/package.json
@@ -25,12 +25,12 @@
"just-scripts": "^1.3.3",
"prettier": "^2.4.1",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-platform-override": "^1.6.6"
},
"peerDependencies": {
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423"
+ "react-native": "0.0.0-20220227-2009-189c2c895"
},
"beachball": {
"defaultNpmTag": "canary",
diff --git a/packages/@react-native/repo-config/overrides.json b/packages/@react-native/repo-config/overrides.json
index 13873d87ae8..72d289e142c 100644
--- a/packages/@react-native/repo-config/overrides.json
+++ b/packages/@react-native/repo-config/overrides.json
@@ -1,11 +1,11 @@
{
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "copy",
"file": "package.json",
"baseFile": "repo-config/package.json",
- "baseHash": "8b5f3ea2a9fc8b90c7c51de7b08c1336a9d1c7b4"
+ "baseHash": "e3b88e4a659e95b76939b54abda030da0ca7f3e3"
}
]
}
\ No newline at end of file
diff --git a/packages/@react-native/repo-config/package.json b/packages/@react-native/repo-config/package.json
index 388f8bf6e6a..2972f7e612f 100644
--- a/packages/@react-native/repo-config/package.json
+++ b/packages/@react-native/repo-config/package.json
@@ -18,7 +18,7 @@
"babel-eslint": "^10.1.0",
"clang-format": "^1.2.4",
"connect": "^3.6.5",
- "coveralls": "^3.0.2",
+ "coveralls": "^3.1.1",
"eslint": "^7.32.0",
"eslint-config-fb-strict": "^26.0.0",
"eslint-config-fbjs": "^3.1.1",
@@ -38,7 +38,7 @@
"jest": "^26.6.3",
"jest-junit": "^10.0.0",
"jscodeshift": "^0.13.1",
- "metro-babel-register": "0.67.0",
+ "metro-babel-register": "0.68.0",
"mkdirp": "^0.5.1",
"prettier": "^2.4.1",
"react": "17.0.2",
diff --git a/packages/@react-native/tester/overrides.json b/packages/@react-native/tester/overrides.json
index e993f187d2c..61bff9c6d95 100644
--- a/packages/@react-native/tester/overrides.json
+++ b/packages/@react-native/tester/overrides.json
@@ -1,5 +1,5 @@
{
- "baseVersion": "0.0.0-20220213-2008-7cece3423",
+ "baseVersion": "0.0.0-20220227-2009-189c2c895",
"overrides": [
{
"type": "copy",
diff --git a/packages/e2e-test-app/package.json b/packages/e2e-test-app/package.json
index 019a3510eb8..472609ba0bd 100644
--- a/packages/e2e-test-app/package.json
+++ b/packages/e2e-test-app/package.json
@@ -16,7 +16,7 @@
"@react-native-windows/automation-channel": "^0.1.44",
"@react-native-windows/tester": "0.0.1",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470",
"react-native-xaml": "^0.0.50"
},
@@ -52,4 +52,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/packages/integration-test-app/package.json b/packages/integration-test-app/package.json
index 4a122d335b4..e4205d00504 100644
--- a/packages/integration-test-app/package.json
+++ b/packages/integration-test-app/package.json
@@ -14,7 +14,7 @@
"@react-native-windows/fs": "^1.0.2",
"chai": "^4.2.0",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470"
},
"devDependencies": {
@@ -50,4 +50,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/packages/playground/package.json b/packages/playground/package.json
index 96bb6d394f1..84b9be14aba 100644
--- a/packages/playground/package.json
+++ b/packages/playground/package.json
@@ -13,7 +13,7 @@
"@react-native-picker/picker": "2.2.0",
"@react-native-windows/tester": "0.0.1",
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470"
},
"devDependencies": {
@@ -38,4 +38,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/packages/sample-apps/package.json b/packages/sample-apps/package.json
index 9f467713323..7f06eb9042f 100644
--- a/packages/sample-apps/package.json
+++ b/packages/sample-apps/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"react": "17.0.2",
- "react-native": "0.0.0-20220213-2008-7cece3423",
+ "react-native": "0.0.0-20220227-2009-189c2c895",
"react-native-windows": "^0.0.0-canary.470"
},
"devDependencies": {
@@ -36,4 +36,4 @@
"engines": {
"node": ">= 14"
}
-}
+}
\ No newline at end of file
diff --git a/vnext/.flowconfig b/vnext/.flowconfig
index 74d99d8938e..cbca5116211 100644
--- a/vnext/.flowconfig
+++ b/vnext/.flowconfig
@@ -58,6 +58,8 @@
; Ignore the src folder - flow files are combined with ones from react-native into the root Libraries folder
.*/vnext/src/.*
+.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
+
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
diff --git a/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp b/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp
index f5aa9be9524..420e72b9834 100644
--- a/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp
+++ b/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp
@@ -306,6 +306,15 @@ PropNameID JsiAbiRuntime::createPropNameIDFromString(const String &str) try {
throw;
}
+PropNameID JsiAbiRuntime::createPropNameIDFromSymbol(const Symbol &sym) {
+ // TODO: Support for symbols through the native API in JSC is very limited.
+ // While we could construct a PropNameID here, we would not be able to get a
+ // symbol property through the C++ API.
+ UNREFERENCED_PARAMETER(sym);
+ RethrowJsiError();
+ throw;
+}
+
std::string JsiAbiRuntime::utf8(const PropNameID &propertyId) try {
std::string dataResult;
m_runtime.PropertyIdToUtf8(AsJsiPropertyIdRef(propertyId), [&dataResult](array_view utf8) {
@@ -1004,4 +1013,4 @@ JsiAbiRuntime::PropNameIDRef::operator facebook::jsi::PropNameID const &() const
} // namespace winrt::Microsoft::ReactNative
-#pragma warning(pop)
\ No newline at end of file
+#pragma warning(pop)
diff --git a/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h b/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h
index 6be1dad3351..1c3db3fb410 100644
--- a/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h
+++ b/vnext/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h
@@ -99,6 +99,7 @@ struct JsiAbiRuntime : facebook::jsi::Runtime {
facebook::jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override;
facebook::jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override;
facebook::jsi::PropNameID createPropNameIDFromString(const facebook::jsi::String &str) override;
+ facebook::jsi::PropNameID createPropNameIDFromSymbol(const facebook::jsi::Symbol &sym);
std::string utf8(const facebook::jsi::PropNameID &propertyNameId) override;
bool compare(const facebook::jsi::PropNameID &left, const facebook::jsi::PropNameID &right) override;
diff --git a/vnext/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp b/vnext/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp
index c46029e47a3..174809996f6 100644
--- a/vnext/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp
+++ b/vnext/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp
@@ -137,6 +137,7 @@ struct NapiJsiRuntime : facebook::jsi::Runtime {
facebook::jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override;
facebook::jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override;
facebook::jsi::PropNameID createPropNameIDFromString(const facebook::jsi::String &str) override;
+ facebook::jsi::PropNameID createPropNameIDFromSymbol(const facebook::jsi::Symbol &sym);
std::string utf8(const facebook::jsi::PropNameID &id) override;
bool compare(const facebook::jsi::PropNameID &lhs, const facebook::jsi::PropNameID &rhs) override;
@@ -711,6 +712,14 @@ PropNameID NapiJsiRuntime::createPropNameIDFromString(const String &str) {
return MakePointer(uniqueStr);
}
+PropNameID NapiJsiRuntime::createPropNameIDFromSymbol(const Symbol &sym) {
+ // TODO: Support for symbols through the native API in JSC is very limited.
+ // While we could construct a PropNameID here, we would not be able to get a
+ // symbol property through the C++ API.
+ UNREFERENCED_PARAMETER(sym);
+ throw;
+}
+
string NapiJsiRuntime::utf8(const PropNameID &id) {
EnvScope scope{m_env};
diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/JSCRuntime.cpp b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/JSCRuntime.cpp
new file mode 100644
index 00000000000..58804af1739
--- /dev/null
+++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/JSCRuntime.cpp
@@ -0,0 +1,1480 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "JSCRuntime.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace facebook {
+namespace jsc {
+
+namespace detail {
+class ArgsConverter;
+} // namespace detail
+
+class JSCRuntime;
+
+struct Lock {
+ void lock(const jsc::JSCRuntime &) const {}
+ void unlock(const jsc::JSCRuntime &) const {}
+};
+
+class JSCRuntime : public jsi::Runtime {
+ public:
+ // Creates new context in new context group
+ JSCRuntime();
+ // Retains ctx
+ JSCRuntime(JSGlobalContextRef ctx);
+ ~JSCRuntime();
+
+ std::shared_ptr prepareJavaScript(
+ const std::shared_ptr &buffer,
+ std::string sourceURL) override;
+
+ jsi::Value evaluatePreparedJavaScript(
+ const std::shared_ptr &js) override;
+
+ jsi::Value evaluateJavaScript(
+ const std::shared_ptr &buffer,
+ const std::string &sourceURL) override;
+
+ bool drainMicrotasks(int maxMicrotasksHint = -1) override;
+
+ jsi::Object global() override;
+
+ std::string description() override;
+
+ bool isInspectable() override;
+
+ void setDescription(const std::string &desc);
+
+ // Please don't use the following two functions, only exposed for
+ // integration efforts.
+ JSGlobalContextRef getContext() {
+ return ctx_;
+ }
+
+ // JSValueRef->JSValue (needs make.*Value so it must be member function)
+ jsi::Value createValue(JSValueRef value) const;
+
+ // Value->JSValueRef (similar to above)
+ JSValueRef valueRef(const jsi::Value &value);
+
+ protected:
+ friend class detail::ArgsConverter;
+ class JSCSymbolValue final : public PointerValue {
+#ifndef NDEBUG
+ JSCSymbolValue(
+ JSGlobalContextRef ctx,
+ const std::atomic &ctxInvalid,
+ JSValueRef sym,
+ std::atomic &counter);
+#else
+ JSCSymbolValue(
+ JSGlobalContextRef ctx,
+ const std::atomic &ctxInvalid,
+ JSValueRef sym);
+#endif
+ void invalidate() override;
+
+ JSGlobalContextRef ctx_;
+ const std::atomic &ctxInvalid_;
+ // There is no C type in the JSC API to represent Symbol, so this stored
+ // a JSValueRef which contains the Symbol.
+ JSValueRef sym_;
+#ifndef NDEBUG
+ std::atomic &counter_;
+#endif
+ protected:
+ friend class JSCRuntime;
+ };
+
+ class JSCStringValue final : public PointerValue {
+#ifndef NDEBUG
+ JSCStringValue(JSStringRef str, std::atomic &counter);
+#else
+ JSCStringValue(JSStringRef str);
+#endif
+ void invalidate() override;
+
+ JSStringRef str_;
+#ifndef NDEBUG
+ std::atomic &counter_;
+#endif
+ protected:
+ friend class JSCRuntime;
+ };
+
+ class JSCObjectValue final : public PointerValue {
+ JSCObjectValue(
+ JSGlobalContextRef ctx,
+ const std::atomic &ctxInvalid,
+ JSObjectRef obj
+#ifndef NDEBUG
+ ,
+ std::atomic &counter
+#endif
+ );
+
+ void invalidate() override;
+
+ JSGlobalContextRef ctx_;
+ const std::atomic &ctxInvalid_;
+ JSObjectRef obj_;
+#ifndef NDEBUG
+ std::atomic &counter_;
+#endif
+ protected:
+ friend class JSCRuntime;
+ };
+
+ PointerValue *cloneSymbol(const Runtime::PointerValue *pv) override;
+ PointerValue *cloneString(const Runtime::PointerValue *pv) override;
+ PointerValue *cloneObject(const Runtime::PointerValue *pv) override;
+ PointerValue *clonePropNameID(const Runtime::PointerValue *pv) override;
+
+ jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length)
+ override;
+ jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length)
+ override;
+ jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override;
+ std::string utf8(const jsi::PropNameID &) override;
+ bool compare(const jsi::PropNameID &, const jsi::PropNameID &) override;
+
+ std::string symbolToString(const jsi::Symbol &) override;
+
+ jsi::String createStringFromAscii(const char *str, size_t length) override;
+ jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override;
+ std::string utf8(const jsi::String &) override;
+
+ jsi::Object createObject() override;
+ jsi::Object createObject(std::shared_ptr ho) override;
+ virtual std::shared_ptr getHostObject(
+ const jsi::Object &) override;
+ jsi::HostFunctionType &getHostFunction(const jsi::Function &) override;
+
+ jsi::Value getProperty(const jsi::Object &, const jsi::String &name) override;
+ jsi::Value getProperty(const jsi::Object &, const jsi::PropNameID &name)
+ override;
+ bool hasProperty(const jsi::Object &, const jsi::String &name) override;
+ bool hasProperty(const jsi::Object &, const jsi::PropNameID &name) override;
+ void setPropertyValue(
+ jsi::Object &,
+ const jsi::String &name,
+ const jsi::Value &value) override;
+ void setPropertyValue(
+ jsi::Object &,
+ const jsi::PropNameID &name,
+ const jsi::Value &value) override;
+ bool isArray(const jsi::Object &) const override;
+ bool isArrayBuffer(const jsi::Object &) const override;
+ bool isFunction(const jsi::Object &) const override;
+ bool isHostObject(const jsi::Object &) const override;
+ bool isHostFunction(const jsi::Function &) const override;
+ jsi::Array getPropertyNames(const jsi::Object &) override;
+
+ // TODO: revisit this implementation
+ jsi::WeakObject createWeakObject(const jsi::Object &) override;
+ jsi::Value lockWeakObject(jsi::WeakObject &) override;
+
+ jsi::Array createArray(size_t length) override;
+ size_t size(const jsi::Array &) override;
+ size_t size(const jsi::ArrayBuffer &) override;
+ uint8_t *data(const jsi::ArrayBuffer &) override;
+ jsi::Value getValueAtIndex(const jsi::Array &, size_t i) override;
+ void setValueAtIndexImpl(jsi::Array &, size_t i, const jsi::Value &value)
+ override;
+
+ jsi::Function createFunctionFromHostFunction(
+ const jsi::PropNameID &name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func) override;
+ jsi::Value call(
+ const jsi::Function &,
+ const jsi::Value &jsThis,
+ const jsi::Value *args,
+ size_t count) override;
+ jsi::Value callAsConstructor(
+ const jsi::Function &,
+ const jsi::Value *args,
+ size_t count) override;
+
+ bool strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const override;
+ bool strictEquals(const jsi::String &a, const jsi::String &b) const override;
+ bool strictEquals(const jsi::Object &a, const jsi::Object &b) const override;
+ bool instanceOf(const jsi::Object &o, const jsi::Function &f) override;
+
+ private:
+ // Basically convenience casts
+ static JSValueRef symbolRef(const jsi::Symbol &str);
+ static JSStringRef stringRef(const jsi::String &str);
+ static JSStringRef stringRef(const jsi::PropNameID &sym);
+ static JSObjectRef objectRef(const jsi::Object &obj);
+
+#ifdef RN_FABRIC_ENABLED
+ static JSObjectRef objectRef(const jsi::WeakObject &obj);
+#endif
+
+ // Factory methods for creating String/Object
+ jsi::Symbol createSymbol(JSValueRef symbolRef) const;
+ jsi::String createString(JSStringRef stringRef) const;
+ jsi::PropNameID createPropNameID(JSStringRef stringRef);
+ jsi::Object createObject(JSObjectRef objectRef) const;
+
+ // Used by factory methods and clone methods
+ jsi::Runtime::PointerValue *makeSymbolValue(JSValueRef sym) const;
+ jsi::Runtime::PointerValue *makeStringValue(JSStringRef str) const;
+ jsi::Runtime::PointerValue *makeObjectValue(JSObjectRef obj) const;
+
+ void checkException(JSValueRef exc);
+ void checkException(JSValueRef res, JSValueRef exc);
+ void checkException(JSValueRef exc, const char *msg);
+ void checkException(JSValueRef res, JSValueRef exc, const char *msg);
+
+ JSGlobalContextRef ctx_;
+ std::atomic ctxInvalid_;
+ std::string desc_;
+#ifndef NDEBUG
+ mutable std::atomic objectCounter_;
+ mutable std::atomic symbolCounter_;
+ mutable std::atomic stringCounter_;
+#endif
+};
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if __has_builtin(__builtin_expect) || defined(__GNUC__)
+#define JSC_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define JSC_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define JSC_LIKELY(EXPR) (EXPR)
+#define JSC_UNLIKELY(EXPR) (EXPR)
+#endif
+
+#define JSC_ASSERT(x) \
+ do { \
+ if (JSC_UNLIKELY(!!(x))) { \
+ abort(); \
+ } \
+ } while (0)
+
+#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+// This takes care of watch and tvos (due to backwards compatibility in
+// Availability.h
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+#define _JSC_FAST_IS_ARRAY
+#endif
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0
+#define _JSC_NO_ARRAY_BUFFERS
+#endif
+#endif
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11
+// Only one of these should be set for a build. If somehow that's not
+// true, this will be a compile-time error and it can be resolved when
+// we understand why.
+#define _JSC_FAST_IS_ARRAY
+#endif
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12
+#define _JSC_NO_ARRAY_BUFFERS
+#endif
+#endif
+
+// JSStringRef utilities
+namespace {
+std::string JSStringToSTLString(JSStringRef str) {
+ // Small string optimization: Avoid one heap allocation for strings that fit
+ // in stackBuffer.size() bytes of UTF-8 (including the null terminator).
+ std::array stackBuffer;
+ std::unique_ptr heapBuffer;
+ char *buffer;
+ // NOTE: By definition, maxBytes >= 1 since the null terminator is included.
+ size_t maxBytes = JSStringGetMaximumUTF8CStringSize(str);
+ if (maxBytes <= stackBuffer.size()) {
+ buffer = stackBuffer.data();
+ } else {
+ heapBuffer = std::make_unique(maxBytes);
+ buffer = heapBuffer.get();
+ }
+ size_t actualBytes = JSStringGetUTF8CString(str, buffer, maxBytes);
+ if (!actualBytes) {
+ // Happens if maxBytes == 0 (never the case here) or if str contains
+ // invalid UTF-16 data, since JSStringGetUTF8CString attempts a strict
+ // conversion.
+ // When converting an invalid string, JSStringGetUTF8CString writes a null
+ // terminator before returning. So we can reliably treat our buffer as a C
+ // string and return the truncated data to our caller. This is slightly
+ // slower than if we knew the length (like below) but better than crashing.
+ // TODO(T62295565): Perform a non-strict, best effort conversion of the
+ // full string instead, like we did before the JSI migration.
+ return std::string(buffer);
+ }
+ return std::string(buffer, actualBytes - 1);
+}
+
+JSStringRef getLengthString() {
+ static JSStringRef length = JSStringCreateWithUTF8CString("length");
+ return length;
+}
+
+JSStringRef getNameString() {
+ static JSStringRef name = JSStringCreateWithUTF8CString("name");
+ return name;
+}
+
+JSStringRef getFunctionString() {
+ static JSStringRef func = JSStringCreateWithUTF8CString("Function");
+ return func;
+}
+
+#if !defined(_JSC_FAST_IS_ARRAY)
+JSStringRef getArrayString() {
+ static JSStringRef array = JSStringCreateWithUTF8CString("Array");
+ return array;
+}
+
+JSStringRef getIsArrayString() {
+ static JSStringRef isArray = JSStringCreateWithUTF8CString("isArray");
+ return isArray;
+}
+#endif
+} // namespace
+
+// std::string utility
+namespace {
+std::string to_string(void *value) {
+ std::ostringstream ss;
+ ss << value;
+ return ss.str();
+}
+} // namespace
+
+JSCRuntime::JSCRuntime()
+ : JSCRuntime(JSGlobalContextCreateInGroup(nullptr, nullptr)) {
+ JSGlobalContextRelease(ctx_);
+}
+
+JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
+ : ctx_(JSGlobalContextRetain(ctx)),
+ ctxInvalid_(false)
+#ifndef NDEBUG
+ ,
+ objectCounter_(0),
+ stringCounter_(0)
+#endif
+{
+}
+
+JSCRuntime::~JSCRuntime() {
+ // On shutting down and cleaning up: when JSC is actually torn down,
+ // it calls JSC::Heap::lastChanceToFinalize internally which
+ // finalizes anything left over. But at this point,
+ // JSValueUnprotect() can no longer be called. We use an
+ // atomic to avoid unsafe unprotects happening after shutdown
+ // has started.
+ ctxInvalid_ = true;
+ JSGlobalContextRelease(ctx_);
+#ifndef NDEBUG
+ assert(
+ objectCounter_ == 0 && "JSCRuntime destroyed with a dangling API object");
+ assert(
+ stringCounter_ == 0 && "JSCRuntime destroyed with a dangling API string");
+#endif
+}
+
+std::shared_ptr JSCRuntime::prepareJavaScript(
+ const std::shared_ptr &buffer,
+ std::string sourceURL) {
+ return std::make_shared(
+ buffer, std::move(sourceURL));
+}
+
+jsi::Value JSCRuntime::evaluatePreparedJavaScript(
+ const std::shared_ptr &js) {
+ assert(
+ dynamic_cast(js.get()) &&
+ "preparedJavaScript must be a SourceJavaScriptPreparation");
+ auto sourceJs =
+ std::static_pointer_cast(js);
+ return evaluateJavaScript(sourceJs, sourceJs->sourceURL());
+}
+
+jsi::Value JSCRuntime::evaluateJavaScript(
+ const std::shared_ptr &buffer,
+ const std::string &sourceURL) {
+ std::string tmp(
+ reinterpret_cast(buffer->data()), buffer->size());
+ JSStringRef sourceRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ JSStringRef sourceURLRef = nullptr;
+ if (!sourceURL.empty()) {
+ sourceURLRef = JSStringCreateWithUTF8CString(sourceURL.c_str());
+ }
+ JSValueRef exc = nullptr;
+ JSValueRef res =
+ JSEvaluateScript(ctx_, sourceRef, nullptr, sourceURLRef, 0, &exc);
+ JSStringRelease(sourceRef);
+ if (sourceURLRef) {
+ JSStringRelease(sourceURLRef);
+ }
+ checkException(res, exc);
+ return createValue(res);
+}
+
+bool JSCRuntime::drainMicrotasks(int maxMicrotasksHint) {
+ return true;
+}
+
+jsi::Object JSCRuntime::global() {
+ return createObject(JSContextGetGlobalObject(ctx_));
+}
+
+std::string JSCRuntime::description() {
+ if (desc_.empty()) {
+ desc_ = std::string("";
+ }
+ return desc_;
+}
+
+bool JSCRuntime::isInspectable() {
+ return false;
+}
+
+namespace {
+
+bool smellsLikeES6Symbol(JSGlobalContextRef ctx, JSValueRef ref) {
+ // Since iOS 13, JSValueGetType will return kJSTypeSymbol
+ // Before: Empirically, an es6 Symbol is not an object, but its type is
+ // object. This makes no sense, but we'll run with it.
+ // https://github.com/WebKit/webkit/blob/master/Source/JavaScriptCore/API/JSValueRef.cpp#L79-L82
+
+ JSType type = JSValueGetType(ctx, ref);
+
+ if (type == /* kJSTypeSymbol */ 6) {
+ return true;
+ }
+
+ return (!JSValueIsObject(ctx, ref) && type == kJSTypeObject);
+}
+
+} // namespace
+
+JSCRuntime::JSCSymbolValue::JSCSymbolValue(
+ JSGlobalContextRef ctx,
+ const std::atomic &ctxInvalid,
+ JSValueRef sym
+#ifndef NDEBUG
+ ,
+ std::atomic &counter
+#endif
+ )
+ : ctx_(ctx),
+ ctxInvalid_(ctxInvalid),
+ sym_(sym)
+#ifndef NDEBUG
+ ,
+ counter_(counter)
+#endif
+{
+ assert(smellsLikeES6Symbol(ctx_, sym_));
+ JSValueProtect(ctx_, sym_);
+#ifndef NDEBUG
+ counter_ += 1;
+#endif
+}
+
+void JSCRuntime::JSCSymbolValue::invalidate() {
+#ifndef NDEBUG
+ counter_ -= 1;
+#endif
+
+ if (!ctxInvalid_) {
+ JSValueUnprotect(ctx_, sym_);
+ }
+ delete this;
+}
+
+#ifndef NDEBUG
+JSCRuntime::JSCStringValue::JSCStringValue(
+ JSStringRef str,
+ std::atomic &counter)
+ : str_(JSStringRetain(str)), counter_(counter) {
+ // Since std::atomic returns a copy instead of a reference when calling
+ // operator+= we must do this explicitly in the constructor
+ counter_ += 1;
+}
+#else
+JSCRuntime::JSCStringValue::JSCStringValue(JSStringRef str)
+ : str_(JSStringRetain(str)) {}
+#endif
+
+void JSCRuntime::JSCStringValue::invalidate() {
+ // These JSC{String,Object}Value objects are implicitly owned by the
+ // {String,Object} objects, thus when a String/Object is destructed
+ // the JSC{String,Object}Value should be released.
+#ifndef NDEBUG
+ counter_ -= 1;
+#endif
+ JSStringRelease(str_);
+ // Angery reaccs only
+ delete this;
+}
+
+JSCRuntime::JSCObjectValue::JSCObjectValue(
+ JSGlobalContextRef ctx,
+ const std::atomic &ctxInvalid,
+ JSObjectRef obj
+#ifndef NDEBUG
+ ,
+ std::atomic &counter
+#endif
+ )
+ : ctx_(ctx),
+ ctxInvalid_(ctxInvalid),
+ obj_(obj)
+#ifndef NDEBUG
+ ,
+ counter_(counter)
+#endif
+{
+ JSValueProtect(ctx_, obj_);
+#ifndef NDEBUG
+ counter_ += 1;
+#endif
+}
+
+void JSCRuntime::JSCObjectValue::invalidate() {
+#ifndef NDEBUG
+ counter_ -= 1;
+#endif
+ // When shutting down the VM, if there is a HostObject which
+ // contains or otherwise owns a jsi::Object, then the final GC will
+ // finalize the HostObject, leading to a call to invalidate(). But
+ // at that point, making calls to JSValueUnprotect will crash.
+ // It is up to the application to make sure that any other calls to
+ // invalidate() happen before VM destruction; see the comment on
+ // jsi::Runtime.
+ //
+ // Another potential concern here is that in the non-shutdown case,
+ // if a HostObject is GCd, JSValueUnprotect will be called from the
+ // JSC finalizer. The documentation warns against this: "You must
+ // not call any function that may cause a garbage collection or an
+ // allocation of a garbage collected object from within a
+ // JSObjectFinalizeCallback. This includes all functions that have a
+ // JSContextRef parameter." However, an audit of the source code for
+ // JSValueUnprotect in late 2018 shows that it cannot cause
+ // allocation or a GC, and further, this code has not changed in
+ // about two years. In the future, we may choose to reintroduce the
+ // mechanism previously used here which uses a separate thread for
+ // JSValueUnprotect, in order to conform to the documented API, but
+ // use the "unsafe" synchronous version on iOS 11 and earlier.
+
+ if (!ctxInvalid_) {
+ JSValueUnprotect(ctx_, obj_);
+ }
+ delete this;
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::cloneSymbol(
+ const jsi::Runtime::PointerValue *pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCSymbolValue *symbol = static_cast(pv);
+ return makeSymbolValue(symbol->sym_);
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::cloneString(
+ const jsi::Runtime::PointerValue *pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCStringValue *string = static_cast(pv);
+ return makeStringValue(string->str_);
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::cloneObject(
+ const jsi::Runtime::PointerValue *pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCObjectValue *object = static_cast(pv);
+ assert(
+ object->ctx_ == ctx_ &&
+ "Don't try to clone an object backed by a different Runtime");
+ return makeObjectValue(object->obj_);
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::clonePropNameID(
+ const jsi::Runtime::PointerValue *pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCStringValue *string = static_cast(pv);
+ return makeStringValue(string->str_);
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromAscii(
+ const char *str,
+ size_t length) {
+ // For system JSC this must is identical to a string
+ std::string tmp(str, length);
+ JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ auto res = createPropNameID(strRef);
+ JSStringRelease(strRef);
+ return res;
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromUtf8(
+ const uint8_t *utf8,
+ size_t length) {
+ std::string tmp(reinterpret_cast(utf8), length);
+ JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ auto res = createPropNameID(strRef);
+ JSStringRelease(strRef);
+ return res;
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromString(const jsi::String &str) {
+ return createPropNameID(stringRef(str));
+}
+
+std::string JSCRuntime::utf8(const jsi::PropNameID &sym) {
+ return JSStringToSTLString(stringRef(sym));
+}
+
+bool JSCRuntime::compare(const jsi::PropNameID &a, const jsi::PropNameID &b) {
+ return JSStringIsEqual(stringRef(a), stringRef(b));
+}
+
+std::string JSCRuntime::symbolToString(const jsi::Symbol &sym) {
+ return jsi::Value(*this, sym).toString(*this).utf8(*this);
+}
+
+jsi::String JSCRuntime::createStringFromAscii(const char *str, size_t length) {
+ // Yes we end up double casting for semantic reasons (UTF8 contains ASCII,
+ // not the other way around)
+ return this->createStringFromUtf8(
+ reinterpret_cast(str), length);
+}
+
+jsi::String JSCRuntime::createStringFromUtf8(
+ const uint8_t *str,
+ size_t length) {
+ std::string tmp(reinterpret_cast(str), length);
+ JSStringRef stringRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ auto result = createString(stringRef);
+ JSStringRelease(stringRef);
+ return result;
+}
+
+std::string JSCRuntime::utf8(const jsi::String &str) {
+ return JSStringToSTLString(stringRef(str));
+}
+
+jsi::Object JSCRuntime::createObject() {
+ return createObject(static_cast(nullptr));
+}
+
+// HostObject details
+namespace detail {
+struct HostObjectProxyBase {
+ HostObjectProxyBase(
+ JSCRuntime &rt,
+ const std::shared_ptr &sho)
+ : runtime(rt), hostObject(sho) {}
+
+ JSCRuntime &runtime;
+ std::shared_ptr hostObject;
+};
+} // namespace detail
+
+namespace {
+std::once_flag hostObjectClassOnceFlag;
+JSClassRef hostObjectClass{};
+} // namespace
+
+jsi::Object JSCRuntime::createObject(std::shared_ptr ho) {
+ struct HostObjectProxy : public detail::HostObjectProxyBase {
+ static JSValueRef getProperty(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSStringRef propName,
+ JSValueRef *exception) {
+ auto proxy = static_cast(JSObjectGetPrivate(object));
+ auto &rt = proxy->runtime;
+ jsi::PropNameID sym = rt.createPropNameID(propName);
+ jsi::Value ret;
+ try {
+ ret = proxy->hostObject->get(rt, sym);
+ } catch (const jsi::JSError &error) {
+ *exception = rt.valueRef(error.value());
+ return JSValueMakeUndefined(ctx);
+ } catch (const std::exception &ex) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::get(propName:") +
+ JSStringToSTLString(propName) + std::string("): ") +
+ ex.what());
+ *exception = rt.valueRef(excValue);
+ return JSValueMakeUndefined(ctx);
+ } catch (...) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::get(propName:") +
+ JSStringToSTLString(propName) +
+ std::string("): "));
+ *exception = rt.valueRef(excValue);
+ return JSValueMakeUndefined(ctx);
+ }
+ return rt.valueRef(ret);
+ }
+
+#define JSC_UNUSED(x) (void)(x);
+
+ static bool setProperty(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSStringRef propName,
+ JSValueRef value,
+ JSValueRef *exception) {
+ JSC_UNUSED(ctx);
+ auto proxy = static_cast(JSObjectGetPrivate(object));
+ auto &rt = proxy->runtime;
+ jsi::PropNameID sym = rt.createPropNameID(propName);
+ try {
+ proxy->hostObject->set(rt, sym, rt.createValue(value));
+ } catch (const jsi::JSError &error) {
+ *exception = rt.valueRef(error.value());
+ return false;
+ } catch (const std::exception &ex) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::set(propName:") +
+ JSStringToSTLString(propName) + std::string("): ") +
+ ex.what());
+ *exception = rt.valueRef(excValue);
+ return false;
+ } catch (...) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::set(propName:") +
+ JSStringToSTLString(propName) +
+ std::string("): "));
+ *exception = rt.valueRef(excValue);
+ return false;
+ }
+ return true;
+ }
+
+ // JSC does not provide means to communicate errors from this callback,
+ // so the error handling strategy is very brutal - we'll just crash
+ // due to noexcept.
+ static void getPropertyNames(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSPropertyNameAccumulatorRef propertyNames) noexcept {
+ JSC_UNUSED(ctx);
+ auto proxy = static_cast(JSObjectGetPrivate(object));
+ auto &rt = proxy->runtime;
+ auto names = proxy->hostObject->getPropertyNames(rt);
+ for (auto &name : names) {
+ JSPropertyNameAccumulatorAddName(propertyNames, stringRef(name));
+ }
+ }
+
+#undef JSC_UNUSED
+
+ static void finalize(JSObjectRef obj) {
+ auto hostObject = static_cast(JSObjectGetPrivate(obj));
+ JSObjectSetPrivate(obj, nullptr);
+ delete hostObject;
+ }
+
+ using HostObjectProxyBase::HostObjectProxyBase;
+ };
+
+ std::call_once(hostObjectClassOnceFlag, []() {
+ JSClassDefinition hostObjectClassDef = kJSClassDefinitionEmpty;
+ hostObjectClassDef.version = 0;
+ hostObjectClassDef.attributes = kJSClassAttributeNoAutomaticPrototype;
+ hostObjectClassDef.finalize = HostObjectProxy::finalize;
+ hostObjectClassDef.getProperty = HostObjectProxy::getProperty;
+ hostObjectClassDef.setProperty = HostObjectProxy::setProperty;
+ hostObjectClassDef.getPropertyNames = HostObjectProxy::getPropertyNames;
+ hostObjectClass = JSClassCreate(&hostObjectClassDef);
+ });
+
+ JSObjectRef obj =
+ JSObjectMake(ctx_, hostObjectClass, new HostObjectProxy(*this, ho));
+ return createObject(obj);
+}
+
+std::shared_ptr JSCRuntime::getHostObject(
+ const jsi::Object &obj) {
+ // We are guaranteed at this point to have isHostObject(obj) == true
+ // so the private data should be HostObjectMetadata
+ JSObjectRef object = objectRef(obj);
+ auto metadata =
+ static_cast(JSObjectGetPrivate(object));
+ assert(metadata);
+ return metadata->hostObject;
+}
+
+jsi::Value JSCRuntime::getProperty(
+ const jsi::Object &obj,
+ const jsi::String &name) {
+ JSObjectRef objRef = objectRef(obj);
+ JSValueRef exc = nullptr;
+ JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+jsi::Value JSCRuntime::getProperty(
+ const jsi::Object &obj,
+ const jsi::PropNameID &name) {
+ JSObjectRef objRef = objectRef(obj);
+ JSValueRef exc = nullptr;
+ JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+bool JSCRuntime::hasProperty(const jsi::Object &obj, const jsi::String &name) {
+ JSObjectRef objRef = objectRef(obj);
+ return JSObjectHasProperty(ctx_, objRef, stringRef(name));
+}
+
+bool JSCRuntime::hasProperty(
+ const jsi::Object &obj,
+ const jsi::PropNameID &name) {
+ JSObjectRef objRef = objectRef(obj);
+ return JSObjectHasProperty(ctx_, objRef, stringRef(name));
+}
+
+void JSCRuntime::setPropertyValue(
+ jsi::Object &object,
+ const jsi::PropNameID &name,
+ const jsi::Value &value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx_,
+ objectRef(object),
+ stringRef(name),
+ valueRef(value),
+ kJSPropertyAttributeNone,
+ &exc);
+ checkException(exc);
+}
+
+void JSCRuntime::setPropertyValue(
+ jsi::Object &object,
+ const jsi::String &name,
+ const jsi::Value &value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx_,
+ objectRef(object),
+ stringRef(name),
+ valueRef(value),
+ kJSPropertyAttributeNone,
+ &exc);
+ checkException(exc);
+}
+
+bool JSCRuntime::isArray(const jsi::Object &obj) const {
+#if !defined(_JSC_FAST_IS_ARRAY)
+ JSObjectRef global = JSContextGetGlobalObject(ctx_);
+ JSStringRef arrayString = getArrayString();
+ JSValueRef exc = nullptr;
+ JSValueRef arrayCtorValue =
+ JSObjectGetProperty(ctx_, global, arrayString, &exc);
+ JSC_ASSERT(exc);
+ JSObjectRef arrayCtor = JSValueToObject(ctx_, arrayCtorValue, &exc);
+ JSC_ASSERT(exc);
+ JSStringRef isArrayString = getIsArrayString();
+ JSValueRef isArrayValue =
+ JSObjectGetProperty(ctx_, arrayCtor, isArrayString, &exc);
+ JSC_ASSERT(exc);
+ JSObjectRef isArray = JSValueToObject(ctx_, isArrayValue, &exc);
+ JSC_ASSERT(exc);
+ JSValueRef arg = objectRef(obj);
+ JSValueRef result =
+ JSObjectCallAsFunction(ctx_, isArray, nullptr, 1, &arg, &exc);
+ JSC_ASSERT(exc);
+ return JSValueToBoolean(ctx_, result);
+#else
+ return JSValueIsArray(ctx_, objectRef(obj));
+#endif
+}
+
+bool JSCRuntime::isArrayBuffer(const jsi::Object &obj) const {
+#if defined(_JSC_NO_ARRAY_BUFFERS)
+ throw std::runtime_error("Unsupported");
+#else
+ auto typedArrayType = JSValueGetTypedArrayType(ctx_, objectRef(obj), nullptr);
+ return typedArrayType == kJSTypedArrayTypeArrayBuffer;
+#endif
+}
+
+uint8_t *JSCRuntime::data(const jsi::ArrayBuffer &obj) {
+#if defined(_JSC_NO_ARRAY_BUFFERS)
+ throw std::runtime_error("Unsupported");
+#else
+ return static_cast(
+ JSObjectGetArrayBufferBytesPtr(ctx_, objectRef(obj), nullptr));
+#endif
+}
+
+size_t JSCRuntime::size(const jsi::ArrayBuffer &obj) {
+#if defined(_JSC_NO_ARRAY_BUFFERS)
+ throw std::runtime_error("Unsupported");
+#else
+ return JSObjectGetArrayBufferByteLength(ctx_, objectRef(obj), nullptr);
+#endif
+}
+
+bool JSCRuntime::isFunction(const jsi::Object &obj) const {
+ return JSObjectIsFunction(ctx_, objectRef(obj));
+}
+
+bool JSCRuntime::isHostObject(const jsi::Object &obj) const {
+ auto cls = hostObjectClass;
+ return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
+}
+
+// Very expensive
+jsi::Array JSCRuntime::getPropertyNames(const jsi::Object &obj) {
+ JSPropertyNameArrayRef names =
+ JSObjectCopyPropertyNames(ctx_, objectRef(obj));
+ size_t len = JSPropertyNameArrayGetCount(names);
+ // Would be better if we could create an array with explicit elements
+ auto result = createArray(len);
+ for (size_t i = 0; i < len; i++) {
+ JSStringRef str = JSPropertyNameArrayGetNameAtIndex(names, i);
+ result.setValueAtIndex(*this, i, createString(str));
+ }
+ JSPropertyNameArrayRelease(names);
+ return result;
+}
+
+jsi::WeakObject JSCRuntime::createWeakObject(const jsi::Object &obj) {
+#ifdef RN_FABRIC_ENABLED
+ // TODO: revisit this implementation
+ JSObjectRef objRef = objectRef(obj);
+ return make(makeObjectValue(objRef));
+#else
+ throw std::logic_error("Not implemented");
+#endif
+}
+
+jsi::Value JSCRuntime::lockWeakObject(jsi::WeakObject &obj) {
+#ifdef RN_FABRIC_ENABLED
+ // TODO: revisit this implementation
+ JSObjectRef objRef = objectRef(obj);
+ return jsi::Value(createObject(objRef));
+#else
+ throw std::logic_error("Not implemented");
+#endif
+}
+
+jsi::Array JSCRuntime::createArray(size_t length) {
+ JSValueRef exc = nullptr;
+ JSObjectRef obj = JSObjectMakeArray(ctx_, 0, nullptr, &exc);
+ checkException(obj, exc);
+ JSObjectSetProperty(
+ ctx_,
+ obj,
+ getLengthString(),
+ JSValueMakeNumber(ctx_, static_cast(length)),
+ 0,
+ &exc);
+ checkException(exc);
+ return createObject(obj).getArray(*this);
+}
+
+size_t JSCRuntime::size(const jsi::Array &arr) {
+ return static_cast(
+ getProperty(arr, createPropNameID(getLengthString())).getNumber());
+}
+
+jsi::Value JSCRuntime::getValueAtIndex(const jsi::Array &arr, size_t i) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectGetPropertyAtIndex(ctx_, objectRef(arr), (int)i, &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+void JSCRuntime::setValueAtIndexImpl(
+ jsi::Array &arr,
+ size_t i,
+ const jsi::Value &value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetPropertyAtIndex(
+ ctx_, objectRef(arr), (int)i, valueRef(value), &exc);
+ checkException(exc);
+}
+
+namespace {
+std::once_flag hostFunctionClassOnceFlag;
+JSClassRef hostFunctionClass{};
+
+class HostFunctionProxy {
+ public:
+ HostFunctionProxy(jsi::HostFunctionType hostFunction)
+ : hostFunction_(hostFunction) {}
+
+ jsi::HostFunctionType &getHostFunction() {
+ return hostFunction_;
+ }
+
+ protected:
+ jsi::HostFunctionType hostFunction_;
+};
+} // namespace
+
+jsi::Function JSCRuntime::createFunctionFromHostFunction(
+ const jsi::PropNameID &name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func) {
+ class HostFunctionMetadata : public HostFunctionProxy {
+ public:
+ static void initialize(JSContextRef ctx, JSObjectRef object) {
+ // We need to set up the prototype chain properly here. In theory we
+ // could set func.prototype.prototype = Function.prototype to get the
+ // same result. Not sure which approach is better.
+ HostFunctionMetadata *metadata =
+ static_cast(JSObjectGetPrivate(object));
+
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx,
+ object,
+ getLengthString(),
+ JSValueMakeNumber(ctx, metadata->argCount),
+ kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
+ kJSPropertyAttributeDontDelete,
+ &exc);
+ if (exc) {
+ // Silently fail to set length
+ exc = nullptr;
+ }
+
+ JSStringRef name = nullptr;
+ std::swap(metadata->name, name);
+ JSObjectSetProperty(
+ ctx,
+ object,
+ getNameString(),
+ JSValueMakeString(ctx, name),
+ kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
+ kJSPropertyAttributeDontDelete,
+ &exc);
+ JSStringRelease(name);
+ if (exc) {
+ // Silently fail to set name
+ exc = nullptr;
+ }
+
+ JSObjectRef global = JSContextGetGlobalObject(ctx);
+ JSValueRef value =
+ JSObjectGetProperty(ctx, global, getFunctionString(), &exc);
+ // If we don't have Function then something bad is going on.
+ if (JSC_UNLIKELY(exc)) {
+ abort();
+ }
+ JSObjectRef funcCtor = JSValueToObject(ctx, value, &exc);
+ if (!funcCtor) {
+ // We can't do anything if Function is not an object
+ return;
+ }
+ JSValueRef funcProto = JSObjectGetPrototype(ctx, funcCtor);
+ JSObjectSetPrototype(ctx, object, funcProto);
+ }
+
+ static JSValueRef makeError(JSCRuntime &rt, const std::string &desc) {
+ jsi::Value value =
+ rt.global().getPropertyAsFunction(rt, "Error").call(rt, desc);
+ return rt.valueRef(value);
+ }
+
+ static JSValueRef call(
+ JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception) {
+ HostFunctionMetadata *metadata =
+ static_cast(JSObjectGetPrivate(function));
+ JSCRuntime &rt = *(metadata->runtime);
+ const unsigned maxStackArgCount = 8;
+ jsi::Value stackArgs[maxStackArgCount];
+ std::unique_ptr heapArgs;
+ jsi::Value *args;
+ if (argumentCount > maxStackArgCount) {
+ heapArgs = std::make_unique(argumentCount);
+ for (size_t i = 0; i < argumentCount; i++) {
+ heapArgs[i] = rt.createValue(arguments[i]);
+ }
+ args = heapArgs.get();
+ } else {
+ for (size_t i = 0; i < argumentCount; i++) {
+ stackArgs[i] = rt.createValue(arguments[i]);
+ }
+ args = stackArgs;
+ }
+ JSValueRef res;
+ jsi::Value thisVal(rt.createObject(thisObject));
+ try {
+ res = rt.valueRef(
+ metadata->hostFunction_(rt, thisVal, args, argumentCount));
+ } catch (const jsi::JSError &error) {
+ *exception = rt.valueRef(error.value());
+ res = JSValueMakeUndefined(ctx);
+ } catch (const std::exception &ex) {
+ std::string exceptionString("Exception in HostFunction: ");
+ exceptionString += ex.what();
+ *exception = makeError(rt, exceptionString);
+ res = JSValueMakeUndefined(ctx);
+ } catch (...) {
+ std::string exceptionString("Exception in HostFunction: ");
+ *exception = makeError(rt, exceptionString);
+ res = JSValueMakeUndefined(ctx);
+ }
+ return res;
+ }
+
+ static void finalize(JSObjectRef object) {
+ HostFunctionMetadata *metadata =
+ static_cast(JSObjectGetPrivate(object));
+ JSObjectSetPrivate(object, nullptr);
+ delete metadata;
+ }
+
+ HostFunctionMetadata(
+ JSCRuntime *rt,
+ jsi::HostFunctionType hf,
+ unsigned ac,
+ JSStringRef n)
+ : HostFunctionProxy(hf),
+ runtime(rt),
+ argCount(ac),
+ name(JSStringRetain(n)) {}
+
+ JSCRuntime *runtime;
+ unsigned argCount;
+ JSStringRef name;
+ };
+
+ std::call_once(hostFunctionClassOnceFlag, []() {
+ JSClassDefinition functionClass = kJSClassDefinitionEmpty;
+ functionClass.version = 0;
+ functionClass.attributes = kJSClassAttributeNoAutomaticPrototype;
+ functionClass.initialize = HostFunctionMetadata::initialize;
+ functionClass.finalize = HostFunctionMetadata::finalize;
+ functionClass.callAsFunction = HostFunctionMetadata::call;
+
+ hostFunctionClass = JSClassCreate(&functionClass);
+ });
+
+ JSObjectRef funcRef = JSObjectMake(
+ ctx_,
+ hostFunctionClass,
+ new HostFunctionMetadata(this, func, paramCount, stringRef(name)));
+ return createObject(funcRef).getFunction(*this);
+}
+
+namespace detail {
+
+class ArgsConverter {
+ public:
+ ArgsConverter(JSCRuntime &rt, const jsi::Value *args, size_t count) {
+ JSValueRef *destination = inline_;
+ if (count > maxStackArgs) {
+ outOfLine_ = std::make_unique(count);
+ destination = outOfLine_.get();
+ }
+
+ for (size_t i = 0; i < count; ++i) {
+ destination[i] = rt.valueRef(args[i]);
+ }
+ }
+
+ operator JSValueRef *() {
+ return outOfLine_ ? outOfLine_.get() : inline_;
+ }
+
+ private:
+ constexpr static unsigned maxStackArgs = 8;
+ JSValueRef inline_[maxStackArgs];
+ std::unique_ptr outOfLine_;
+};
+} // namespace detail
+
+bool JSCRuntime::isHostFunction(const jsi::Function &obj) const {
+ auto cls = hostFunctionClass;
+ return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
+}
+
+jsi::HostFunctionType &JSCRuntime::getHostFunction(const jsi::Function &obj) {
+ // We know that isHostFunction(obj) is true here, so its safe to proceed
+ auto proxy =
+ static_cast(JSObjectGetPrivate(objectRef(obj)));
+ return proxy->getHostFunction();
+}
+
+jsi::Value JSCRuntime::call(
+ const jsi::Function &f,
+ const jsi::Value &jsThis,
+ const jsi::Value *args,
+ size_t count) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectCallAsFunction(
+ ctx_,
+ objectRef(f),
+ jsThis.isUndefined() ? nullptr : objectRef(jsThis.getObject(*this)),
+ count,
+ detail::ArgsConverter(*this, args, count),
+ &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+jsi::Value JSCRuntime::callAsConstructor(
+ const jsi::Function &f,
+ const jsi::Value *args,
+ size_t count) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectCallAsConstructor(
+ ctx_,
+ objectRef(f),
+ count,
+ detail::ArgsConverter(*this, args, count),
+ &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+bool JSCRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b)
+ const {
+ JSValueRef exc = nullptr;
+ bool ret = JSValueIsEqual(ctx_, symbolRef(a), symbolRef(b), &exc);
+ const_cast(this)->checkException(exc);
+ return ret;
+}
+
+bool JSCRuntime::strictEquals(const jsi::String &a, const jsi::String &b)
+ const {
+ return JSStringIsEqual(stringRef(a), stringRef(b));
+}
+
+bool JSCRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b)
+ const {
+ return objectRef(a) == objectRef(b);
+}
+
+bool JSCRuntime::instanceOf(const jsi::Object &o, const jsi::Function &f) {
+ JSValueRef exc = nullptr;
+ bool res =
+ JSValueIsInstanceOfConstructor(ctx_, objectRef(o), objectRef(f), &exc);
+ checkException(exc);
+ return res;
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::makeSymbolValue(
+ JSValueRef symbolRef) const {
+#ifndef NDEBUG
+ return new JSCSymbolValue(ctx_, ctxInvalid_, symbolRef, symbolCounter_);
+#else
+ return new JSCSymbolValue(ctx_, ctxInvalid_, symbolRef);
+#endif
+}
+
+namespace {
+JSStringRef getEmptyString() {
+ static JSStringRef empty = JSStringCreateWithUTF8CString("");
+ return empty;
+}
+} // namespace
+
+jsi::Runtime::PointerValue *JSCRuntime::makeStringValue(
+ JSStringRef stringRef) const {
+ if (!stringRef) {
+ stringRef = getEmptyString();
+ }
+#ifndef NDEBUG
+ return new JSCStringValue(stringRef, stringCounter_);
+#else
+ return new JSCStringValue(stringRef);
+#endif
+}
+
+jsi::Symbol JSCRuntime::createSymbol(JSValueRef sym) const {
+ return make(makeSymbolValue(sym));
+}
+
+jsi::String JSCRuntime::createString(JSStringRef str) const {
+ return make(makeStringValue(str));
+}
+
+jsi::PropNameID JSCRuntime::createPropNameID(JSStringRef str) {
+ return make(makeStringValue(str));
+}
+
+jsi::Runtime::PointerValue *JSCRuntime::makeObjectValue(
+ JSObjectRef objectRef) const {
+ if (!objectRef) {
+ objectRef = JSObjectMake(ctx_, nullptr, nullptr);
+ }
+#ifndef NDEBUG
+ return new JSCObjectValue(ctx_, ctxInvalid_, objectRef, objectCounter_);
+#else
+ return new JSCObjectValue(ctx_, ctxInvalid_, objectRef);
+#endif
+}
+
+jsi::Object JSCRuntime::createObject(JSObjectRef obj) const {
+ return make(makeObjectValue(obj));
+}
+
+jsi::Value JSCRuntime::createValue(JSValueRef value) const {
+ JSType type = JSValueGetType(ctx_, value);
+
+ switch (type) {
+ case kJSTypeNumber:
+ return jsi::Value(JSValueToNumber(ctx_, value, nullptr));
+ case kJSTypeBoolean:
+ return jsi::Value(JSValueToBoolean(ctx_, value));
+ case kJSTypeNull:
+ return jsi::Value(nullptr);
+ case kJSTypeUndefined:
+ return jsi::Value();
+ case kJSTypeString: {
+ JSStringRef str = JSValueToStringCopy(ctx_, value, nullptr);
+ auto result = jsi::Value(createString(str));
+ JSStringRelease(str);
+ return result;
+ }
+ case kJSTypeObject: {
+ JSObjectRef objRef = JSValueToObject(ctx_, value, nullptr);
+ return jsi::Value(createObject(objRef));
+ }
+ // TODO: Uncomment this when all supported JSC versions have this symbol
+ // case kJSTypeSymbol:
+ default: {
+ if (smellsLikeES6Symbol(ctx_, value)) {
+ return jsi::Value(createSymbol(value));
+ } else {
+ // WHAT ARE YOU
+ abort();
+ }
+ }
+ }
+}
+
+JSValueRef JSCRuntime::valueRef(const jsi::Value &value) {
+ // I would rather switch on value.kind_
+ if (value.isUndefined()) {
+ return JSValueMakeUndefined(ctx_);
+ } else if (value.isNull()) {
+ return JSValueMakeNull(ctx_);
+ } else if (value.isBool()) {
+ return JSValueMakeBoolean(ctx_, value.getBool());
+ } else if (value.isNumber()) {
+ return JSValueMakeNumber(ctx_, value.getNumber());
+ } else if (value.isSymbol()) {
+ return symbolRef(value.getSymbol(*this));
+ } else if (value.isString()) {
+ return JSValueMakeString(ctx_, stringRef(value.getString(*this)));
+ } else if (value.isObject()) {
+ return objectRef(value.getObject(*this));
+ } else {
+ // What are you?
+ abort();
+ }
+}
+
+JSValueRef JSCRuntime::symbolRef(const jsi::Symbol &sym) {
+ return static_cast(getPointerValue(sym))->sym_;
+}
+
+JSStringRef JSCRuntime::stringRef(const jsi::String &str) {
+ return static_cast(getPointerValue(str))->str_;
+}
+
+JSStringRef JSCRuntime::stringRef(const jsi::PropNameID &sym) {
+ return static_cast(getPointerValue(sym))->str_;
+}
+
+JSObjectRef JSCRuntime::objectRef(const jsi::Object &obj) {
+ return static_cast(getPointerValue(obj))->obj_;
+}
+
+#ifdef RN_FABRIC_ENABLED
+JSObjectRef JSCRuntime::objectRef(const jsi::WeakObject &obj) {
+ // TODO: revisit this implementation
+ return static_cast(getPointerValue(obj))->obj_;
+}
+#endif
+
+void JSCRuntime::checkException(JSValueRef exc) {
+ if (JSC_UNLIKELY(exc)) {
+ throw jsi::JSError(*this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(JSValueRef res, JSValueRef exc) {
+ if (JSC_UNLIKELY(!res)) {
+ throw jsi::JSError(*this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(JSValueRef exc, const char *msg) {
+ if (JSC_UNLIKELY(exc)) {
+ throw jsi::JSError(std::string(msg), *this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(
+ JSValueRef res,
+ JSValueRef exc,
+ const char *msg) {
+ if (JSC_UNLIKELY(!res)) {
+ throw jsi::JSError(std::string(msg), *this, createValue(exc));
+ }
+}
+
+std::unique_ptr makeJSCRuntime() {
+ return std::make_unique();
+}
+
+} // namespace jsc
+} // namespace facebook
diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/decorator.h b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/decorator.h
new file mode 100644
index 00000000000..a3619544459
--- /dev/null
+++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/decorator.h
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include
+
+#include
+#include
+
+// This file contains objects to help API users create their own
+// runtime adapters, i.e. if you want to compose runtimes to add your
+// own behavior.
+
+namespace facebook {
+namespace jsi {
+
+// Use this to wrap host functions. It will pass the member runtime as
+// the first arg to the callback. The first argument to the ctor
+// should be the decorated runtime, not the plain one.
+class DecoratedHostFunction {
+ public:
+ DecoratedHostFunction(Runtime& drt, HostFunctionType plainHF)
+ : drt_(drt), plainHF_(std::move(plainHF)) {}
+
+ Runtime& decoratedRuntime() {
+ return drt_;
+ }
+
+ Value
+ operator()(Runtime&, const Value& thisVal, const Value* args, size_t count) {
+ return plainHF_(decoratedRuntime(), thisVal, args, count);
+ }
+
+ private:
+ template
+ friend class RuntimeDecorator;
+
+ Runtime& drt_;
+ HostFunctionType plainHF_;
+};
+
+// From the perspective of the caller, a plain HostObject is passed to
+// the decorated Runtime, and the HostObject methods expect to get
+// passed that Runtime. But the plain Runtime will pass itself to its
+// callback, so we need a helper here which curries the decorated
+// Runtime, and calls the plain HostObject with it.
+//
+// If the concrete RuntimeDecorator derives DecoratedHostObject, it
+// should call the base class get() and set() to invoke the plain
+// HostObject functionality. The Runtime& it passes does not matter,
+// as it is not used.
+class DecoratedHostObject : public HostObject {
+ public:
+ DecoratedHostObject(Runtime& drt, std::shared_ptr plainHO)
+ : drt_(drt), plainHO_(plainHO) {}
+
+ // The derived class methods can call this to get a reference to the
+ // decorated runtime, since the rt passed to the callback will be
+ // the plain runtime.
+ Runtime& decoratedRuntime() {
+ return drt_;
+ }
+
+ Value get(Runtime&, const PropNameID& name) override {
+ return plainHO_->get(decoratedRuntime(), name);
+ }
+
+ void set(Runtime&, const PropNameID& name, const Value& value) override {
+ plainHO_->set(decoratedRuntime(), name, value);
+ }
+
+ std::vector getPropertyNames(Runtime&) override {
+ return plainHO_->getPropertyNames(decoratedRuntime());
+ }
+
+ private:
+ template
+ friend class RuntimeDecorator;
+
+ Runtime& drt_;
+ std::shared_ptr plainHO_;
+};
+
+/// C++ variant on a standard Decorator pattern, using template
+/// parameters. The \c Plain template parameter type is the
+/// undecorated Runtime type. You can usually use \c Runtime here,
+/// but if you know the concrete type ahead of time and it's final,
+/// the compiler can devirtualize calls to the decorated
+/// implementation. The \c Base template parameter type will be used
+/// as the base class of the decorated type. Here, too, you can
+/// usually use \c Runtime, but if you want the decorated type to
+/// implement a derived class of Runtime, you can specify that here.
+/// For an example, see threadsafe.h.
+template
+class RuntimeDecorator : public Base, private jsi::Instrumentation {
+ public:
+ Plain& plain() {
+ static_assert(
+ std::is_base_of::value,
+ "RuntimeDecorator's Plain type must derive from jsi::Runtime");
+ static_assert(
+ std::is_base_of::value,
+ "RuntimeDecorator's Base type must derive from jsi::Runtime");
+ return plain_;
+ }
+ const Plain& plain() const {
+ return plain_;
+ }
+
+ Value evaluateJavaScript(
+ const std::shared_ptr& buffer,
+ const std::string& sourceURL) override {
+ return plain().evaluateJavaScript(buffer, sourceURL);
+ }
+ std::shared_ptr prepareJavaScript(
+ const std::shared_ptr& buffer,
+ std::string sourceURL) override {
+ return plain().prepareJavaScript(buffer, std::move(sourceURL));
+ }
+ Value evaluatePreparedJavaScript(
+ const std::shared_ptr& js) override {
+ return plain().evaluatePreparedJavaScript(js);
+ }
+ bool drainMicrotasks(int maxMicrotasksHint) override {
+ return plain().drainMicrotasks(maxMicrotasksHint);
+ }
+ Object global() override {
+ return plain().global();
+ }
+ std::string description() override {
+ return plain().description();
+ };
+ bool isInspectable() override {
+ return plain().isInspectable();
+ };
+ Instrumentation& instrumentation() override {
+ return *this;
+ }
+
+ protected:
+ // plain is generally going to be a reference to an object managed
+ // by a derived class. We cache it here so this class can be
+ // concrete, and avoid making virtual calls to find the plain
+ // Runtime. Note that the ctor and dtor do not access through the
+ // reference, so passing a reference to an object before its
+ // lifetime has started is ok.
+ RuntimeDecorator(Plain& plain) : plain_(plain) {}
+
+ Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override {
+ return plain_.cloneSymbol(pv);
+ };
+ Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override {
+ return plain_.cloneString(pv);
+ };
+ Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override {
+ return plain_.cloneObject(pv);
+ };
+ Runtime::PointerValue* clonePropNameID(
+ const Runtime::PointerValue* pv) override {
+ return plain_.clonePropNameID(pv);
+ };
+
+ PropNameID createPropNameIDFromAscii(const char* str, size_t length)
+ override {
+ return plain_.createPropNameIDFromAscii(str, length);
+ };
+ PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length)
+ override {
+ return plain_.createPropNameIDFromUtf8(utf8, length);
+ };
+ PropNameID createPropNameIDFromString(const String& str) override {
+ return plain_.createPropNameIDFromString(str);
+ };
+ std::string utf8(const PropNameID& id) override {
+ return plain_.utf8(id);
+ };
+ bool compare(const PropNameID& a, const PropNameID& b) override {
+ return plain_.compare(a, b);
+ };
+
+ std::string symbolToString(const Symbol& sym) override {
+ return plain_.symbolToString(sym);
+ }
+
+ String createStringFromAscii(const char* str, size_t length) override {
+ return plain_.createStringFromAscii(str, length);
+ };
+ String createStringFromUtf8(const uint8_t* utf8, size_t length) override {
+ return plain_.createStringFromUtf8(utf8, length);
+ };
+ std::string utf8(const String& s) override {
+ return plain_.utf8(s);
+ }
+
+ Object createObject() override {
+ return plain_.createObject();
+ };
+
+ Object createObject(std::shared_ptr ho) override {
+ return plain_.createObject(
+ std::make_shared(*this, std::move(ho)));
+ };
+ std::shared_ptr getHostObject(const jsi::Object& o) override {
+ std::shared_ptr dho = plain_.getHostObject(o);
+ return static_cast(*dho).plainHO_;
+ };
+ HostFunctionType& getHostFunction(const jsi::Function& f) override {
+ HostFunctionType& dhf = plain_.getHostFunction(f);
+ // This will fail if a cpp file including this header is not compiled
+ // with RTTI.
+ return dhf.target()->plainHF_;
+ };
+
+ Value getProperty(const Object& o, const PropNameID& name) override {
+ return plain_.getProperty(o, name);
+ };
+ Value getProperty(const Object& o, const String& name) override {
+ return plain_.getProperty(o, name);
+ };
+ bool hasProperty(const Object& o, const PropNameID& name) override {
+ return plain_.hasProperty(o, name);
+ };
+ bool hasProperty(const Object& o, const String& name) override {
+ return plain_.hasProperty(o, name);
+ };
+ void setPropertyValue(Object& o, const PropNameID& name, const Value& value)
+ override {
+ plain_.setPropertyValue(o, name, value);
+ };
+ void setPropertyValue(Object& o, const String& name, const Value& value)
+ override {
+ plain_.setPropertyValue(o, name, value);
+ };
+
+ bool isArray(const Object& o) const override {
+ return plain_.isArray(o);
+ };
+ bool isArrayBuffer(const Object& o) const override {
+ return plain_.isArrayBuffer(o);
+ };
+ bool isFunction(const Object& o) const override {
+ return plain_.isFunction(o);
+ };
+ bool isHostObject(const jsi::Object& o) const override {
+ return plain_.isHostObject(o);
+ };
+ bool isHostFunction(const jsi::Function& f) const override {
+ return plain_.isHostFunction(f);
+ };
+ Array getPropertyNames(const Object& o) override {
+ return plain_.getPropertyNames(o);
+ };
+
+ WeakObject createWeakObject(const Object& o) override {
+ return plain_.createWeakObject(o);
+ };
+ Value lockWeakObject(WeakObject& wo) override {
+ return plain_.lockWeakObject(wo);
+ };
+
+ Array createArray(size_t length) override {
+ return plain_.createArray(length);
+ };
+ size_t size(const Array& a) override {
+ return plain_.size(a);
+ };
+ size_t size(const ArrayBuffer& ab) override {
+ return plain_.size(ab);
+ };
+ uint8_t* data(const ArrayBuffer& ab) override {
+ return plain_.data(ab);
+ };
+ Value getValueAtIndex(const Array& a, size_t i) override {
+ return plain_.getValueAtIndex(a, i);
+ };
+ void setValueAtIndexImpl(Array& a, size_t i, const Value& value) override {
+ plain_.setValueAtIndexImpl(a, i, value);
+ };
+
+ Function createFunctionFromHostFunction(
+ const PropNameID& name,
+ unsigned int paramCount,
+ HostFunctionType func) override {
+ return plain_.createFunctionFromHostFunction(
+ name, paramCount, DecoratedHostFunction(*this, std::move(func)));
+ };
+ Value call(
+ const Function& f,
+ const Value& jsThis,
+ const Value* args,
+ size_t count) override {
+ return plain_.call(f, jsThis, args, count);
+ };
+ Value callAsConstructor(const Function& f, const Value* args, size_t count)
+ override {
+ return plain_.callAsConstructor(f, args, count);
+ };
+
+ // Private data for managing scopes.
+ Runtime::ScopeState* pushScope() override {
+ return plain_.pushScope();
+ }
+ void popScope(Runtime::ScopeState* ss) override {
+ plain_.popScope(ss);
+ }
+
+ bool strictEquals(const Symbol& a, const Symbol& b) const override {
+ return plain_.strictEquals(a, b);
+ };
+ bool strictEquals(const String& a, const String& b) const override {
+ return plain_.strictEquals(a, b);
+ };
+ bool strictEquals(const Object& a, const Object& b) const override {
+ return plain_.strictEquals(a, b);
+ };
+
+ bool instanceOf(const Object& o, const Function& f) override {
+ return plain_.instanceOf(o, f);
+ };
+
+ // jsi::Instrumentation methods
+
+ std::string getRecordedGCStats() override {
+ return plain().instrumentation().getRecordedGCStats();
+ }
+
+ std::unordered_map getHeapInfo(
+ bool includeExpensive) override {
+ return plain().instrumentation().getHeapInfo(includeExpensive);
+ }
+
+ void collectGarbage(std::string cause) override {
+ plain().instrumentation().collectGarbage(std::move(cause));
+ }
+
+ void startTrackingHeapObjectStackTraces(
+ std::function)> callback) override {
+ plain().instrumentation().startTrackingHeapObjectStackTraces(
+ std::move(callback));
+ }
+
+ void stopTrackingHeapObjectStackTraces() override {
+ plain().instrumentation().stopTrackingHeapObjectStackTraces();
+ }
+
+ void startHeapSampling(size_t samplingInterval) override {
+ plain().instrumentation().startHeapSampling(samplingInterval);
+ }
+
+ void stopHeapSampling(std::ostream& os) override {
+ plain().instrumentation().stopHeapSampling(os);
+ }
+
+ void createSnapshotToFile(const std::string& path) override {
+ plain().instrumentation().createSnapshotToFile(path);
+ }
+
+ void createSnapshotToStream(std::ostream& os) override {
+ plain().instrumentation().createSnapshotToStream(os);
+ }
+
+ std::string flushAndDisableBridgeTrafficTrace() override {
+ return const_cast(plain())
+ .instrumentation()
+ .flushAndDisableBridgeTrafficTrace();
+ }
+
+ void writeBasicBlockProfileTraceToFile(
+ const std::string& fileName) const override {
+ const_cast(plain())
+ .instrumentation()
+ .writeBasicBlockProfileTraceToFile(fileName);
+ }
+
+ /// Dump external profiler symbols to the given file name.
+ void dumpProfilerSymbolsToFile(const std::string& fileName) const override {
+ const_cast(plain()).instrumentation().dumpProfilerSymbolsToFile(
+ fileName);
+ }
+
+ private:
+ Plain& plain_;
+};
+
+namespace detail {
+
+// This metaprogramming allows the With type's methods to be
+// optional.
+
+template
+struct BeforeCaller {
+ static void before(T&) {}
+};
+
+template
+struct AfterCaller {
+ static void after(T&) {}
+};
+
+// decltype((void)&...) is either SFINAE, or void.
+// So, if SFINAE does not happen for T, then this specialization exists
+// for BeforeCaller, and always applies. If not, only the
+// default above exists, and that is used instead.
+template
+struct BeforeCaller {
+ static void before(T& t) {
+ t.before();
+ }
+};
+
+template
+struct AfterCaller {
+ static void after(T& t) {
+ t.after();
+ }
+};
+
+// It's possible to use multiple decorators by nesting
+// WithRuntimeDecorator<...>, but this specialization allows use of
+// std::tuple of decorator classes instead. See testlib.cpp for an
+// example.
+template
+struct BeforeCaller> {
+ static void before(std::tuple& tuple) {
+ all_before<0, T...>(tuple);
+ }
+
+ private:
+ template
+ static void all_before(std::tuple& tuple) {
+ detail::BeforeCaller::before(std::get(tuple));
+ all_before(tuple);
+ }
+
+ template
+ static void all_before(std::tuple&) {}
+};
+
+template
+struct AfterCaller> {
+ static void after(std::tuple& tuple) {
+ all_after<0, T...>(tuple);
+ }
+
+ private:
+ template
+ static void all_after(std::tuple& tuple) {
+ all_after(tuple);
+ detail::AfterCaller::after(std::get(tuple));
+ }
+
+ template
+ static void all_after(std::tuple&) {}
+};
+
+} // namespace detail
+
+// A decorator which implements an around idiom. A With instance is
+// RAII constructed before each call to the undecorated class; the
+// ctor is passed a single argument of type WithArg&. Plain and Base
+// are used as in the base class.
+template
+class WithRuntimeDecorator : public RuntimeDecorator {
+ public:
+ using RD = RuntimeDecorator;
+
+ // The reference arguments to the ctor are stored, but not used by
+ // the ctor, and there is no ctor, so they can be passed members of
+ // the derived class.
+ WithRuntimeDecorator(Plain& plain, With& with) : RD(plain), with_(with) {}
+
+ Value evaluateJavaScript(
+ const std::shared_ptr& buffer,
+ const std::string& sourceURL) override {
+ Around around{with_};
+ return RD::evaluateJavaScript(buffer, sourceURL);
+ }
+ std::shared_ptr prepareJavaScript(
+ const std::shared_ptr& buffer,
+ std::string sourceURL) override {
+ Around around{with_};
+ return RD::prepareJavaScript(buffer, std::move(sourceURL));
+ }
+ Value evaluatePreparedJavaScript(
+ const std::shared_ptr& js) override {
+ Around around{with_};
+ return RD::evaluatePreparedJavaScript(js);
+ }
+ bool drainMicrotasks(int maxMicrotasksHint) override {
+ Around around{with_};
+ return RD::drainMicrotasks(maxMicrotasksHint);
+ }
+ Object global() override {
+ Around around{with_};
+ return RD::global();
+ }
+ std::string description() override {
+ Around around{with_};
+ return RD::description();
+ };
+ bool isInspectable() override {
+ Around around{with_};
+ return RD::isInspectable();
+ };
+
+ // The jsi:: prefix is necessary because MSVC compiler complains C2247:
+ // Instrumentation is not accessible because RuntimeDecorator uses private
+ // to inherit from Instrumentation.
+ // TODO(T40821815) Consider removing this workaround when updating MSVC
+ jsi::Instrumentation& instrumentation() override {
+ Around around{with_};
+ return RD::instrumentation();
+ }
+
+ protected:
+ Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override {
+ Around around{with_};
+ return RD::cloneSymbol(pv);
+ };
+ Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override {
+ Around around{with_};
+ return RD::cloneString(pv);
+ };
+ Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override {
+ Around around{with_};
+ return RD::cloneObject(pv);
+ };
+ Runtime::PointerValue* clonePropNameID(
+ const Runtime::PointerValue* pv) override {
+ Around around{with_};
+ return RD::clonePropNameID(pv);
+ };
+
+ PropNameID createPropNameIDFromAscii(const char* str, size_t length)
+ override {
+ Around around{with_};
+ return RD::createPropNameIDFromAscii(str, length);
+ };
+ PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length)
+ override {
+ Around around{with_};
+ return RD::createPropNameIDFromUtf8(utf8, length);
+ };
+ PropNameID createPropNameIDFromString(const String& str) override {
+ Around around{with_};
+ return RD::createPropNameIDFromString(str);
+ };
+ std::string utf8(const PropNameID& id) override {
+ Around around{with_};
+ return RD::utf8(id);
+ };
+ bool compare(const PropNameID& a, const PropNameID& b) override {
+ Around around{with_};
+ return RD::compare(a, b);
+ };
+
+ std::string symbolToString(const Symbol& sym) override {
+ Around around{with_};
+ return RD::symbolToString(sym);
+ };
+
+ String createStringFromAscii(const char* str, size_t length) override {
+ Around around{with_};
+ return RD::createStringFromAscii(str, length);
+ };
+ String createStringFromUtf8(const uint8_t* utf8, size_t length) override {
+ Around around{with_};
+ return RD::createStringFromUtf8(utf8, length);
+ };
+ std::string utf8(const String& s) override {
+ Around around{with_};
+ return RD::utf8(s);
+ }
+
+ Object createObject() override {
+ Around around{with_};
+ return RD::createObject();
+ };
+ Object createObject(std::shared_ptr ho) override {
+ Around around{with_};
+ return RD::createObject(std::move(ho));
+ };
+ std::shared_ptr getHostObject(const jsi::Object& o) override {
+ Around around{with_};
+ return RD::getHostObject(o);
+ };
+ HostFunctionType& getHostFunction(const jsi::Function& f) override {
+ Around around{with_};
+ return RD::getHostFunction(f);
+ };
+
+ Value getProperty(const Object& o, const PropNameID& name) override {
+ Around around{with_};
+ return RD::getProperty(o, name);
+ };
+ Value getProperty(const Object& o, const String& name) override {
+ Around around{with_};
+ return RD::getProperty(o, name);
+ };
+ bool hasProperty(const Object& o, const PropNameID& name) override {
+ Around around{with_};
+ return RD::hasProperty(o, name);
+ };
+ bool hasProperty(const Object& o, const String& name) override {
+ Around around{with_};
+ return RD::hasProperty(o, name);
+ };
+ void setPropertyValue(Object& o, const PropNameID& name, const Value& value)
+ override {
+ Around around{with_};
+ RD::setPropertyValue(o, name, value);
+ };
+ void setPropertyValue(Object& o, const String& name, const Value& value)
+ override {
+ Around around{with_};
+ RD::setPropertyValue(o, name, value);
+ };
+
+ bool isArray(const Object& o) const override {
+ Around around{with_};
+ return RD::isArray(o);
+ };
+ bool isArrayBuffer(const Object& o) const override {
+ Around around{with_};
+ return RD::isArrayBuffer(o);
+ };
+ bool isFunction(const Object& o) const override {
+ Around around{with_};
+ return RD::isFunction(o);
+ };
+ bool isHostObject(const jsi::Object& o) const override {
+ Around around{with_};
+ return RD::isHostObject(o);
+ };
+ bool isHostFunction(const jsi::Function& f) const override {
+ Around around{with_};
+ return RD::isHostFunction(f);
+ };
+ Array getPropertyNames(const Object& o) override {
+ Around around{with_};
+ return RD::getPropertyNames(o);
+ };
+
+ WeakObject createWeakObject(const Object& o) override {
+ Around around{with_};
+ return RD::createWeakObject(o);
+ };
+ Value lockWeakObject(WeakObject& wo) override {
+ Around around{with_};
+ return RD::lockWeakObject(wo);
+ };
+
+ Array createArray(size_t length) override {
+ Around around{with_};
+ return RD::createArray(length);
+ };
+ size_t size(const Array& a) override {
+ Around around{with_};
+ return RD::size(a);
+ };
+ size_t size(const ArrayBuffer& ab) override {
+ Around around{with_};
+ return RD::size(ab);
+ };
+ uint8_t* data(const ArrayBuffer& ab) override {
+ Around around{with_};
+ return RD::data(ab);
+ };
+ Value getValueAtIndex(const Array& a, size_t i) override {
+ Around around{with_};
+ return RD::getValueAtIndex(a, i);
+ };
+ void setValueAtIndexImpl(Array& a, size_t i, const Value& value) override {
+ Around around{with_};
+ RD::setValueAtIndexImpl(a, i, value);
+ };
+
+ Function createFunctionFromHostFunction(
+ const PropNameID& name,
+ unsigned int paramCount,
+ HostFunctionType func) override {
+ Around around{with_};
+ return RD::createFunctionFromHostFunction(
+ name, paramCount, std::move(func));
+ };
+ Value call(
+ const Function& f,
+ const Value& jsThis,
+ const Value* args,
+ size_t count) override {
+ Around around{with_};
+ return RD::call(f, jsThis, args, count);
+ };
+ Value callAsConstructor(const Function& f, const Value* args, size_t count)
+ override {
+ Around around{with_};
+ return RD::callAsConstructor(f, args, count);
+ };
+
+ // Private data for managing scopes.
+ Runtime::ScopeState* pushScope() override {
+ Around around{with_};
+ return RD::pushScope();
+ }
+ void popScope(Runtime::ScopeState* ss) override {
+ Around around{with_};
+ RD::popScope(ss);
+ }
+
+ bool strictEquals(const Symbol& a, const Symbol& b) const override {
+ Around around{with_};
+ return RD::strictEquals(a, b);
+ };
+ bool strictEquals(const String& a, const String& b) const override {
+ Around around{with_};
+ return RD::strictEquals(a, b);
+ };
+ bool strictEquals(const Object& a, const Object& b) const override {
+ Around around{with_};
+ return RD::strictEquals(a, b);
+ };
+
+ bool instanceOf(const Object& o, const Function& f) override {
+ Around around{with_};
+ return RD::instanceOf(o, f);
+ };
+
+ private:
+ // Wrap an RAII type around With& to guarantee after always happens.
+ struct Around {
+ Around(With& with) : with_(with) {
+ detail::BeforeCaller::before(with_);
+ }
+ ~Around() {
+ detail::AfterCaller::after(with_);
+ }
+
+ With& with_;
+ };
+
+ With& with_;
+};
+
+} // namespace jsi
+} // namespace facebook
diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/jsi.h b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/jsi.h
new file mode 100644
index 00000000000..55b9e48c432
--- /dev/null
+++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/jsi.h
@@ -0,0 +1,1321 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef JSI_EXPORT
+#ifdef _MSC_VER
+#ifdef CREATE_SHARED_LIBRARY
+#define JSI_EXPORT __declspec(dllexport)
+#else
+#define JSI_EXPORT
+#endif // CREATE_SHARED_LIBRARY
+#else // _MSC_VER
+#define JSI_EXPORT __attribute__((visibility("default")))
+#endif // _MSC_VER
+#endif // !defined(JSI_EXPORT)
+
+class FBJSRuntime;
+namespace facebook {
+namespace jsi {
+
+class JSI_EXPORT Buffer {
+ public:
+ virtual ~Buffer();
+ virtual size_t size() const = 0;
+ virtual const uint8_t* data() const = 0;
+};
+
+class JSI_EXPORT StringBuffer : public Buffer {
+ public:
+ StringBuffer(std::string s) : s_(std::move(s)) {}
+ size_t size() const override {
+ return s_.size();
+ }
+ const uint8_t* data() const override {
+ return reinterpret_cast(s_.data());
+ }
+
+ private:
+ std::string s_;
+};
+
+/// PreparedJavaScript is a base class representing JavaScript which is in a
+/// form optimized for execution, in a runtime-specific way. Construct one via
+/// jsi::Runtime::prepareJavaScript().
+/// ** This is an experimental API that is subject to change. **
+class JSI_EXPORT PreparedJavaScript {
+ protected:
+ PreparedJavaScript() = default;
+
+ public:
+ virtual ~PreparedJavaScript() = 0;
+};
+
+class Runtime;
+class Pointer;
+class PropNameID;
+class Symbol;
+class String;
+class Object;
+class WeakObject;
+class Array;
+class ArrayBuffer;
+class Function;
+class Value;
+class Instrumentation;
+class Scope;
+class JSIException;
+class JSError;
+
+/// A function which has this type can be registered as a function
+/// callable from JavaScript using Function::createFromHostFunction().
+/// When the function is called, args will point to the arguments, and
+/// count will indicate how many arguments are passed. The function
+/// can return a Value to the caller, or throw an exception. If a C++
+/// exception is thrown, a JS Error will be created and thrown into
+/// JS; if the C++ exception extends std::exception, the Error's
+/// message will be whatever what() returns. Note that it is undefined whether
+/// HostFunctions may or may not be called in strict mode; that is `thisVal`
+/// can be any value - it will not necessarily be coerced to an object or
+/// or set to the global object.
+using HostFunctionType = std::function<
+ Value(Runtime& rt, const Value& thisVal, const Value* args, size_t count)>;
+
+/// An object which implements this interface can be registered as an
+/// Object with the JS runtime.
+class JSI_EXPORT HostObject {
+ public:
+ // The C++ object's dtor will be called when the GC finalizes this
+ // object. (This may be as late as when the Runtime is shut down.)
+ // You have no control over which thread it is called on. This will
+ // be called from inside the GC, so it is unsafe to do any VM
+ // operations which require a Runtime&. Derived classes' dtors
+ // should also avoid doing anything expensive. Calling the dtor on
+ // a jsi object is explicitly ok. If you want to do JS operations,
+ // or any nontrivial work, you should add it to a work queue, and
+ // manage it externally.
+ virtual ~HostObject();
+
+ // When JS wants a property with a given name from the HostObject,
+ // it will call this method. If it throws an exception, the call
+ // will throw a JS \c Error object. By default this returns undefined.
+ // \return the value for the property.
+ virtual Value get(Runtime&, const PropNameID& name);
+
+ // When JS wants to set a property with a given name on the HostObject,
+ // it will call this method. If it throws an exception, the call will
+ // throw a JS \c Error object. By default this throws a type error exception
+ // mimicking the behavior of a frozen object in strict mode.
+ virtual void set(Runtime&, const PropNameID& name, const Value& value);
+
+ // When JS wants a list of property names for the HostObject, it will
+ // call this method. If it throws an exception, the call will throw a
+ // JS \c Error object. The default implementation returns empty vector.
+ virtual std::vector getPropertyNames(Runtime& rt);
+};
+
+/// Represents a JS runtime. Movable, but not copyable. Note that
+/// this object may not be thread-aware, but cannot be used safely from
+/// multiple threads at once. The application is responsible for
+/// ensuring that it is used safely. This could mean using the
+/// Runtime from a single thread, using a mutex, doing all work on a
+/// serial queue, etc. This restriction applies to the methods of
+/// this class, and any method in the API which take a Runtime& as an
+/// argument. Destructors (all but ~Scope), operators, or other methods
+/// which do not take Runtime& as an argument are safe to call from any
+/// thread, but it is still forbidden to make write operations on a single
+/// instance of any class from more than one thread. In addition, to
+/// make shutdown safe, destruction of objects associated with the Runtime
+/// must be destroyed before the Runtime is destroyed, or from the
+/// destructor of a managed HostObject or HostFunction. Informally, this
+/// means that the main source of unsafe behavior is to hold a jsi object
+/// in a non-Runtime-managed object, and not clean it up before the Runtime
+/// is shut down. If your lifecycle is such that avoiding this is hard,
+/// you will probably need to do use your own locks.
+class JSI_EXPORT Runtime {
+ public:
+ virtual ~Runtime();
+
+ /// Evaluates the given JavaScript \c buffer. \c sourceURL is used
+ /// to annotate the stack trace if there is an exception. The
+ /// contents may be utf8-encoded JS source code, or binary bytecode
+ /// whose format is specific to the implementation. If the input
+ /// format is unknown, or evaluation causes an error, a JSIException
+ /// will be thrown.
+ /// Note this function should ONLY be used when there isn't another means
+ /// through the JSI API. For example, it will be much slower to use this to
+ /// call a global function than using the JSI APIs to read the function
+ /// property from the global object and then calling it explicitly.
+ virtual Value evaluateJavaScript(
+ const std::shared_ptr& buffer,
+ const std::string& sourceURL) = 0;
+
+ /// Prepares to evaluate the given JavaScript \c buffer by processing it into
+ /// a form optimized for execution. This may include pre-parsing, compiling,
+ /// etc. If the input is invalid (for example, cannot be parsed), a
+ /// JSIException will be thrown. The resulting object is tied to the
+ /// particular concrete type of Runtime from which it was created. It may be
+ /// used (via evaluatePreparedJavaScript) in any Runtime of the same concrete
+ /// type.
+ /// The PreparedJavaScript object may be passed to multiple VM instances, so
+ /// they can all share and benefit from the prepared script.
+ /// As with evaluateJavaScript(), using JavaScript code should be avoided
+ /// when the JSI API is sufficient.
+ virtual std::shared_ptr prepareJavaScript(
+ const std::shared_ptr& buffer,
+ std::string sourceURL) = 0;
+
+ /// Evaluates a PreparedJavaScript. If evaluation causes an error, a
+ /// JSIException will be thrown.
+ /// As with evaluateJavaScript(), using JavaScript code should be avoided
+ /// when the JSI API is sufficient.
+ virtual Value evaluatePreparedJavaScript(
+ const std::shared_ptr& js) = 0;
+
+ /// Drain the JavaScript VM internal Microtask (a.k.a. Job in ECMA262) queue.
+ ///
+ /// \param maxMicrotasksHint a hint to tell an implementation that it should
+ /// make a best effort not execute more than the given number. It's default
+ /// to -1 for infinity (unbounded execution).
+ /// \return true if the queue is drained or false if there is more work to do.
+ ///
+ /// When there were exceptions thrown from the execution of microtasks,
+ /// implementations shall discard the exceptional jobs. An implementation may
+ /// \throw a \c JSError object to signal the hosts to handle. In that case, an
+ /// implementation may or may not suspend the draining.
+ ///
+ /// Hosts may call this function again to resume the draining if it was
+ /// suspended due to either exceptions or the \p maxMicrotasksHint bound.
+ /// E.g. a host may repetitively invoke this function until the queue is
+ /// drained to implement the "microtask checkpoint" defined in WHATWG HTML
+ /// event loop: https://html.spec.whatwg.org/C#perform-a-microtask-checkpoint.
+ ///
+ /// Note that error propagation is only a concern if a host needs to implement
+ /// `queueMicrotask`, a recent API that allows enqueueing arbitrary functions
+ /// (hence may throw) as microtasks. Exceptions from ECMA-262 Promise Jobs are
+ /// handled internally to VMs and are never propagated to hosts.
+ ///
+ /// This API offers some queue management to hosts at its best effort due to
+ /// different behaviors and limitations imposed by different VMs and APIs. By
+ /// the time this is written, An implementation may swallow exceptions (JSC),
+ /// may not pause (V8), and may not support bounded executions.
+ virtual bool drainMicrotasks(int maxMicrotasksHint = -1) = 0;
+
+ /// \return the global object
+ virtual Object global() = 0;
+
+ /// \return a short printable description of the instance. It should
+ /// at least include some human-readable indication of the runtime
+ /// implementation. This should only be used by logging, debugging,
+ /// and other developer-facing callers.
+ virtual std::string description() = 0;
+
+ /// \return whether or not the underlying runtime supports debugging via the
+ /// Chrome remote debugging protocol.
+ ///
+ /// NOTE: the API for determining whether a runtime is debuggable and
+ /// registering a runtime with the debugger is still in flux, so please don't
+ /// use this API unless you know what you're doing.
+ virtual bool isInspectable() = 0;
+
+ /// \return an interface to extract metrics from this \c Runtime. The default
+ /// implementation of this function returns an \c Instrumentation instance
+ /// which returns no metrics.
+ virtual Instrumentation& instrumentation();
+
+ protected:
+ friend class Pointer;
+ friend class PropNameID;
+ friend class Symbol;
+ friend class String;
+ friend class Object;
+ friend class WeakObject;
+ friend class Array;
+ friend class ArrayBuffer;
+ friend class Function;
+ friend class Value;
+ friend class Scope;
+ friend class JSError;
+
+ // Potential optimization: avoid the cloneFoo() virtual dispatch,
+ // and instead just fix the number of fields, and copy them, since
+ // in practice they are trivially copyable. Sufficient use of
+ // rvalue arguments/methods would also reduce the number of clones.
+
+ struct PointerValue {
+ virtual void invalidate() = 0;
+
+ protected:
+ virtual ~PointerValue() = default;
+ };
+
+ virtual PointerValue* cloneSymbol(const Runtime::PointerValue* pv) = 0;
+ virtual PointerValue* cloneString(const Runtime::PointerValue* pv) = 0;
+ virtual PointerValue* cloneObject(const Runtime::PointerValue* pv) = 0;
+ virtual PointerValue* clonePropNameID(const Runtime::PointerValue* pv) = 0;
+
+ virtual PropNameID createPropNameIDFromAscii(
+ const char* str,
+ size_t length) = 0;
+ virtual PropNameID createPropNameIDFromUtf8(
+ const uint8_t* utf8,
+ size_t length) = 0;
+ virtual PropNameID createPropNameIDFromString(const String& str) = 0;
+ virtual std::string utf8(const PropNameID&) = 0;
+ virtual bool compare(const PropNameID&, const PropNameID&) = 0;
+
+ virtual std::string symbolToString(const Symbol&) = 0;
+
+ virtual String createStringFromAscii(const char* str, size_t length) = 0;
+ virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0;
+ virtual std::string utf8(const String&) = 0;
+
+ // \return a \c Value created from a utf8-encoded JSON string. The default
+ // implementation creates a \c String and invokes JSON.parse.
+ virtual Value createValueFromJsonUtf8(const uint8_t* json, size_t length);
+
+ virtual Object createObject() = 0;
+ virtual Object createObject(std::shared_ptr ho) = 0;
+ virtual std::shared_ptr getHostObject(const jsi::Object&) = 0;
+ virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0;
+
+ virtual Value getProperty(const Object&, const PropNameID& name) = 0;
+ virtual Value getProperty(const Object&, const String& name) = 0;
+ virtual bool hasProperty(const Object&, const PropNameID& name) = 0;
+ virtual bool hasProperty(const Object&, const String& name) = 0;
+ virtual void
+ setPropertyValue(Object&, const PropNameID& name, const Value& value) = 0;
+ virtual void
+ setPropertyValue(Object&, const String& name, const Value& value) = 0;
+
+ virtual bool isArray(const Object&) const = 0;
+ virtual bool isArrayBuffer(const Object&) const = 0;
+ virtual bool isFunction(const Object&) const = 0;
+ virtual bool isHostObject(const jsi::Object&) const = 0;
+ virtual bool isHostFunction(const jsi::Function&) const = 0;
+ virtual Array getPropertyNames(const Object&) = 0;
+
+ virtual WeakObject createWeakObject(const Object&) = 0;
+ virtual Value lockWeakObject(WeakObject&) = 0;
+
+ virtual Array createArray(size_t length) = 0;
+ virtual size_t size(const Array&) = 0;
+ virtual size_t size(const ArrayBuffer&) = 0;
+ virtual uint8_t* data(const ArrayBuffer&) = 0;
+ virtual Value getValueAtIndex(const Array&, size_t i) = 0;
+ virtual void setValueAtIndexImpl(Array&, size_t i, const Value& value) = 0;
+
+ virtual Function createFunctionFromHostFunction(
+ const PropNameID& name,
+ unsigned int paramCount,
+ HostFunctionType func) = 0;
+ virtual Value call(
+ const Function&,
+ const Value& jsThis,
+ const Value* args,
+ size_t count) = 0;
+ virtual Value
+ callAsConstructor(const Function&, const Value* args, size_t count) = 0;
+
+ // Private data for managing scopes.
+ struct ScopeState;
+ virtual ScopeState* pushScope();
+ virtual void popScope(ScopeState*);
+
+ virtual bool strictEquals(const Symbol& a, const Symbol& b) const = 0;
+ virtual bool strictEquals(const String& a, const String& b) const = 0;
+ virtual bool strictEquals(const Object& a, const Object& b) const = 0;
+
+ virtual bool instanceOf(const Object& o, const Function& f) = 0;
+
+ // These exist so derived classes can access the private parts of
+ // Value, Symbol, String, and Object, which are all friends of Runtime.
+ template
+ static T make(PointerValue* pv);
+ static PointerValue* getPointerValue(Pointer& pointer);
+ static const PointerValue* getPointerValue(const Pointer& pointer);
+ static const PointerValue* getPointerValue(const Value& value);
+
+ friend class ::FBJSRuntime;
+ template
+ friend class RuntimeDecorator;
+};
+
+// Base class for pointer-storing types.
+class JSI_EXPORT Pointer {
+ protected:
+ explicit Pointer(Pointer&& other) : ptr_(other.ptr_) {
+ other.ptr_ = nullptr;
+ }
+
+ ~Pointer() {
+ if (ptr_) {
+ ptr_->invalidate();
+ }
+ }
+
+ Pointer& operator=(Pointer&& other);
+
+ friend class Runtime;
+ friend class Value;
+
+ explicit Pointer(Runtime::PointerValue* ptr) : ptr_(ptr) {}
+
+ typename Runtime::PointerValue* ptr_;
+};
+
+/// Represents something that can be a JS property key. Movable, not copyable.
+class JSI_EXPORT PropNameID : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ PropNameID(Runtime& runtime, const PropNameID& other)
+ : Pointer(runtime.clonePropNameID(other.ptr_)) {}
+
+ PropNameID(PropNameID&& other) = default;
+ PropNameID& operator=(PropNameID&& other) = default;
+
+ /// Create a JS property name id from ascii values. The data is
+ /// copied.
+ static PropNameID forAscii(Runtime& runtime, const char* str, size_t length) {
+ return runtime.createPropNameIDFromAscii(str, length);
+ }
+
+ /// Create a property name id from a nul-terminated C ascii name. The data is
+ /// copied.
+ static PropNameID forAscii(Runtime& runtime, const char* str) {
+ return forAscii(runtime, str, strlen(str));
+ }
+
+ /// Create a PropNameID from a C++ string. The string is copied.
+ static PropNameID forAscii(Runtime& runtime, const std::string& str) {
+ return forAscii(runtime, str.c_str(), str.size());
+ }
+
+ /// Create a PropNameID from utf8 values. The data is copied.
+ /// Results are undefined if \p utf8 contains invalid code points.
+ static PropNameID
+ forUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) {
+ return runtime.createPropNameIDFromUtf8(utf8, length);
+ }
+
+ /// Create a PropNameID from utf8-encoded octets stored in a
+ /// std::string. The string data is transformed and copied.
+ /// Results are undefined if \p utf8 contains invalid code points.
+ static PropNameID forUtf8(Runtime& runtime, const std::string& utf8) {
+ return runtime.createPropNameIDFromUtf8(
+ reinterpret_cast(utf8.data()), utf8.size());
+ }
+
+ /// Create a PropNameID from a JS string.
+ static PropNameID forString(Runtime& runtime, const jsi::String& str) {
+ return runtime.createPropNameIDFromString(str);
+ }
+
+ // Creates a vector of PropNameIDs constructed from given arguments.
+ template
+ static std::vector names(Runtime& runtime, Args&&... args);
+
+ // Creates a vector of given PropNameIDs.
+ template
+ static std::vector names(PropNameID(&&propertyNames)[N]);
+
+ /// Copies the data in a PropNameID as utf8 into a C++ string.
+ std::string utf8(Runtime& runtime) const {
+ return runtime.utf8(*this);
+ }
+
+ static bool compare(
+ Runtime& runtime,
+ const jsi::PropNameID& a,
+ const jsi::PropNameID& b) {
+ return runtime.compare(a, b);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+/// Represents a JS Symbol (es6). Movable, not copyable.
+/// TODO T40778724: this is a limited implementation sufficient for
+/// the debugger not to crash when a Symbol is a property in an Object
+/// or element in an array. Complete support for creating will come
+/// later.
+class JSI_EXPORT Symbol : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ Symbol(Symbol&& other) = default;
+ Symbol& operator=(Symbol&& other) = default;
+
+ /// \return whether a and b refer to the same symbol.
+ static bool strictEquals(Runtime& runtime, const Symbol& a, const Symbol& b) {
+ return runtime.strictEquals(a, b);
+ }
+
+ /// Converts a Symbol into a C++ string as JS .toString would. The output
+ /// will look like \c Symbol(description) .
+ std::string toString(Runtime& runtime) const {
+ return runtime.symbolToString(*this);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+/// Represents a JS String. Movable, not copyable.
+class JSI_EXPORT String : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ String(String&& other) = default;
+ String& operator=(String&& other) = default;
+
+ /// Create a JS string from ascii values. The string data is
+ /// copied.
+ static String
+ createFromAscii(Runtime& runtime, const char* str, size_t length) {
+ return runtime.createStringFromAscii(str, length);
+ }
+
+ /// Create a JS string from a nul-terminated C ascii string. The
+ /// string data is copied.
+ static String createFromAscii(Runtime& runtime, const char* str) {
+ return createFromAscii(runtime, str, strlen(str));
+ }
+
+ /// Create a JS string from a C++ string. The string data is
+ /// copied.
+ static String createFromAscii(Runtime& runtime, const std::string& str) {
+ return createFromAscii(runtime, str.c_str(), str.size());
+ }
+
+ /// Create a JS string from utf8-encoded octets. The string data is
+ /// transformed and copied. Results are undefined if \p utf8 contains invalid
+ /// code points.
+ static String
+ createFromUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) {
+ return runtime.createStringFromUtf8(utf8, length);
+ }
+
+ /// Create a JS string from utf8-encoded octets stored in a
+ /// std::string. The string data is transformed and copied. Results are
+ /// undefined if \p utf8 contains invalid code points.
+ static String createFromUtf8(Runtime& runtime, const std::string& utf8) {
+ return runtime.createStringFromUtf8(
+ reinterpret_cast(utf8.data()), utf8.length());
+ }
+
+ /// \return whether a and b contain the same characters.
+ static bool strictEquals(Runtime& runtime, const String& a, const String& b) {
+ return runtime.strictEquals(a, b);
+ }
+
+ /// Copies the data in a JS string as utf8 into a C++ string.
+ std::string utf8(Runtime& runtime) const {
+ return runtime.utf8(*this);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+class Array;
+class Function;
+
+/// Represents a JS Object. Movable, not copyable.
+class JSI_EXPORT Object : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ Object(Object&& other) = default;
+ Object& operator=(Object&& other) = default;
+
+ /// Creates a new Object instance, like '{}' in JS.
+ Object(Runtime& runtime) : Object(runtime.createObject()) {}
+
+ static Object createFromHostObject(
+ Runtime& runtime,
+ std::shared_ptr ho) {
+ return runtime.createObject(ho);
+ }
+
+ /// \return whether this and \c obj are the same JSObject or not.
+ static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) {
+ return runtime.strictEquals(a, b);
+ }
+
+ /// \return the result of `this instanceOf ctor` in JS.
+ bool instanceOf(Runtime& rt, const Function& ctor) {
+ return rt.instanceOf(*this, ctor);
+ }
+
+ /// \return the property of the object with the given ascii name.
+ /// If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const char* name) const;
+
+ /// \return the property of the object with the String name.
+ /// If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const String& name) const;
+
+ /// \return the property of the object with the given JS PropNameID
+ /// name. If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const PropNameID& name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given ascii name.
+ bool hasProperty(Runtime& runtime, const char* name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given String name.
+ bool hasProperty(Runtime& runtime, const String& name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given PropNameID name.
+ bool hasProperty(Runtime& runtime, const PropNameID& name) const;
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template
+ void setProperty(Runtime& runtime, const char* name, T&& value);
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template
+ void setProperty(Runtime& runtime, const String& name, T&& value);
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template
+ void setProperty(Runtime& runtime, const PropNameID& name, T&& value);
+
+ /// \return true iff JS \c Array.isArray() would return \c true. If
+ /// so, then \c getArray() will succeed.
+ bool isArray(Runtime& runtime) const {
+ return runtime.isArray(*this);
+ }
+
+ /// \return true iff the Object is an ArrayBuffer. If so, then \c
+ /// getArrayBuffer() will succeed.
+ bool isArrayBuffer(Runtime& runtime) const {
+ return runtime.isArrayBuffer(*this);
+ }
+
+ /// \return true iff the Object is callable. If so, then \c
+ /// getFunction will succeed.
+ bool isFunction(Runtime& runtime) const {
+ return runtime.isFunction(*this);
+ }
+
+ /// \return true iff the Object was initialized with \c createFromHostObject
+ /// and the HostObject passed is of type \c T. If returns \c true then
+ /// \c getHostObject will succeed.
+ template
+ bool isHostObject(Runtime& runtime) const;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will assert.
+ Array getArray(Runtime& runtime) const&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will assert.
+ Array getArray(Runtime& runtime) &&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will throw
+ /// JSIException.
+ Array asArray(Runtime& runtime) const&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will throw
+ /// JSIException.
+ Array asArray(Runtime& runtime) &&;
+
+ /// \return an ArrayBuffer instance which refers to the same underlying
+ /// object. If \c isArrayBuffer() would return false, this will assert.
+ ArrayBuffer getArrayBuffer(Runtime& runtime) const&;
+
+ /// \return an ArrayBuffer instance which refers to the same underlying
+ /// object. If \c isArrayBuffer() would return false, this will assert.
+ ArrayBuffer getArrayBuffer(Runtime& runtime) &&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will assert.
+ Function getFunction(Runtime& runtime) const&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will assert.
+ Function getFunction(Runtime& runtime) &&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will throw
+ /// JSIException.
+ Function asFunction(Runtime& runtime) const&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will throw
+ /// JSIException.
+ Function asFunction(Runtime& runtime) &&;
+
+ /// \return a shared_ptr which refers to the same underlying
+ /// \c HostObject that was used to create this object. If \c isHostObject
+ /// is false, this will assert. Note that this does a type check and will
+ /// assert if the underlying HostObject isn't of type \c T
+ template
+ std::shared_ptr getHostObject(Runtime& runtime) const;
+
+ /// \return a shared_ptr which refers to the same underlying
+ /// \c HostObject that was used to create this object. If \c isHostObject
+ /// is false, this will throw.
+ template
+ std::shared_ptr asHostObject(Runtime& runtime) const;
+
+ /// \return same as \c getProperty(name).asObject(), except with
+ /// a better exception message.
+ Object getPropertyAsObject(Runtime& runtime, const char* name) const;
+
+ /// \return similar to \c
+ /// getProperty(name).getObject().getFunction(), except it will
+ /// throw JSIException instead of asserting if the property is
+ /// not an object, or the object is not callable.
+ Function getPropertyAsFunction(Runtime& runtime, const char* name) const;
+
+ /// \return an Array consisting of all enumerable property names in
+ /// the object and its prototype chain. All values in the return
+ /// will be isString(). (This is probably not optimal, but it
+ /// works. I only need it in one place.)
+ Array getPropertyNames(Runtime& runtime) const;
+
+ protected:
+ void
+ setPropertyValue(Runtime& runtime, const String& name, const Value& value) {
+ return runtime.setPropertyValue(*this, name, value);
+ }
+
+ void setPropertyValue(
+ Runtime& runtime,
+ const PropNameID& name,
+ const Value& value) {
+ return runtime.setPropertyValue(*this, name, value);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+/// Represents a weak reference to a JS Object. If the only reference
+/// to an Object are these, the object is eligible for GC. Method
+/// names are inspired by C++ weak_ptr. Movable, not copyable.
+class JSI_EXPORT WeakObject : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ WeakObject(WeakObject&& other) = default;
+ WeakObject& operator=(WeakObject&& other) = default;
+
+ /// Create a WeakObject from an Object.
+ WeakObject(Runtime& runtime, const Object& o)
+ : WeakObject(runtime.createWeakObject(o)) {}
+
+ /// \return a Value representing the underlying Object if it is still valid;
+ /// otherwise returns \c undefined. Note that this method has nothing to do
+ /// with threads or concurrency. The name is based on std::weak_ptr::lock()
+ /// which serves a similar purpose.
+ Value lock(Runtime& runtime);
+
+ friend class Runtime;
+};
+
+/// Represents a JS Object which can be efficiently used as an array
+/// with integral indices.
+class JSI_EXPORT Array : public Object {
+ public:
+ Array(Array&&) = default;
+ /// Creates a new Array instance, with \c length undefined elements.
+ Array(Runtime& runtime, size_t length) : Array(runtime.createArray(length)) {}
+
+ Array& operator=(Array&&) = default;
+
+ /// \return the size of the Array, according to its length property.
+ /// (C++ naming convention)
+ size_t size(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ /// \return the size of the Array, according to its length property.
+ /// (JS naming convention)
+ size_t length(Runtime& runtime) const {
+ return size(runtime);
+ }
+
+ /// \return the property of the array at index \c i. If there is no
+ /// such property, returns the undefined value. If \c i is out of
+ /// range [ 0..\c length ] throws a JSIException.
+ Value getValueAtIndex(Runtime& runtime, size_t i) const;
+
+ /// Sets the property of the array at index \c i. The argument
+ /// value behaves as with Object::setProperty(). If \c i is out of
+ /// range [ 0..\c length ] throws a JSIException.
+ template
+ void setValueAtIndex(Runtime& runtime, size_t i, T&& value);
+
+ /// There is no current API for changing the size of an array once
+ /// created. We'll probably need that eventually.
+
+ /// Creates a new Array instance from provided values
+ template
+ static Array createWithElements(Runtime&, Args&&... args);
+
+ /// Creates a new Array instance from initializer list.
+ static Array createWithElements(
+ Runtime& runtime,
+ std::initializer_list elements);
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ void setValueAtIndexImpl(Runtime& runtime, size_t i, const Value& value) {
+ return runtime.setValueAtIndexImpl(*this, i, value);
+ }
+
+ Array(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents a JSArrayBuffer
+class JSI_EXPORT ArrayBuffer : public Object {
+ public:
+ ArrayBuffer(ArrayBuffer&&) = default;
+ ArrayBuffer& operator=(ArrayBuffer&&) = default;
+
+ /// \return the size of the ArrayBuffer, according to its byteLength property.
+ /// (C++ naming convention)
+ size_t size(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ size_t length(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ uint8_t* data(Runtime& runtime) {
+ return runtime.data(*this);
+ }
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ ArrayBuffer(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents a JS Object which is guaranteed to be Callable.
+class JSI_EXPORT Function : public Object {
+ public:
+ Function(Function&&) = default;
+ Function& operator=(Function&&) = default;
+
+ /// Create a function which, when invoked, calls C++ code. If the
+ /// function throws an exception, a JS Error will be created and
+ /// thrown.
+ /// \param name the name property for the function.
+ /// \param paramCount the length property for the function, which
+ /// may not be the number of arguments the function is passed.
+ static Function createFromHostFunction(
+ Runtime& runtime,
+ const jsi::PropNameID& name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func);
+
+ /// Calls the function with \c count \c args. The \c this value of the JS
+ /// function will not be set by the C++ caller, similar to calling
+ /// Function.prototype.apply(undefined, args) in JS.
+ /// \b Note: as with Function.prototype.apply, \c this may not always be
+ /// \c undefined in the function itself. If the function is non-strict,
+ /// \c this will be set to the global object.
+ Value call(Runtime& runtime, const Value* args, size_t count) const;
+
+ /// Calls the function with a \c std::initializer_list of Value
+ /// arguments. The \c this value of the JS function will not be set by the
+ /// C++ caller, similar to calling Function.prototype.apply(undefined, args)
+ /// in JS.
+ /// \b Note: as with Function.prototype.apply, \c this may not always be
+ /// \c undefined in the function itself. If the function is non-strict,
+ /// \c this will be set to the global object.
+ Value call(Runtime& runtime, std::initializer_list args) const;
+
+ /// Calls the function with any number of arguments similarly to
+ /// Object::setProperty(). The \c this value of the JS function will not be
+ /// set by the C++ caller, similar to calling
+ /// Function.prototype.call(undefined, ...args) in JS.
+ /// \b Note: as with Function.prototype.call, \c this may not always be
+ /// \c undefined in the function itself. If the function is non-strict,
+ /// \c this will be set to the global object.
+ template
+ Value call(Runtime& runtime, Args&&... args) const;
+
+ /// Calls the function with \c count \c args and \c jsThis value passed
+ /// as the \c this value.
+ Value callWithThis(
+ Runtime& Runtime,
+ const Object& jsThis,
+ const Value* args,
+ size_t count) const;
+
+ /// Calls the function with a \c std::initializer_list of Value
+ /// arguments and \c jsThis passed as the \c this value.
+ Value callWithThis(
+ Runtime& runtime,
+ const Object& jsThis,
+ std::initializer_list args) const;
+
+ /// Calls the function with any number of arguments similarly to
+ /// Object::setProperty(), and with \c jsThis passed as the \c this value.
+ template
+ Value callWithThis(Runtime& runtime, const Object& jsThis, Args&&... args)
+ const;
+
+ /// Calls the function as a constructor with \c count \c args. Equivalent
+ /// to calling `new Func` where `Func` is the js function reqresented by
+ /// this.
+ Value callAsConstructor(Runtime& runtime, const Value* args, size_t count)
+ const;
+
+ /// Same as above `callAsConstructor`, except use an initializer_list to
+ /// supply the arguments.
+ Value callAsConstructor(Runtime& runtime, std::initializer_list args)
+ const;
+
+ /// Same as above `callAsConstructor`, but automatically converts/wraps
+ /// any argument with a jsi Value.
+ template
+ Value callAsConstructor(Runtime& runtime, Args&&... args) const;
+
+ /// Returns whether this was created with Function::createFromHostFunction.
+ /// If true then you can use getHostFunction to get the underlying
+ /// HostFunctionType.
+ bool isHostFunction(Runtime& runtime) const {
+ return runtime.isHostFunction(*this);
+ }
+
+ /// Returns the underlying HostFunctionType iff isHostFunction returns true
+ /// and asserts otherwise. You can use this to use std::function<>::target
+ /// to get the object that was passed to create the HostFunctionType.
+ ///
+ /// Note: The reference returned is borrowed from the JS object underlying
+ /// \c this, and thus only lasts as long as the object underlying
+ /// \c this does.
+ HostFunctionType& getHostFunction(Runtime& runtime) const {
+ assert(isHostFunction(runtime));
+ return runtime.getHostFunction(*this);
+ }
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ Function(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents any JS Value (undefined, null, boolean, number, symbol,
+/// string, or object). Movable, or explicitly copyable (has no copy
+/// ctor).
+class JSI_EXPORT Value {
+ public:
+ /// Default ctor creates an \c undefined JS value.
+ Value() : Value(UndefinedKind) {}
+
+ /// Creates a \c null JS value.
+ /* implicit */ Value(std::nullptr_t) : kind_(NullKind) {}
+
+ /// Creates a boolean JS value.
+ /* implicit */ Value(bool b) : Value(BooleanKind) {
+ data_.boolean = b;
+ }
+
+ /// Creates a number JS value.
+ /* implicit */ Value(double d) : Value(NumberKind) {
+ data_.number = d;
+ }
+
+ /// Creates a number JS value.
+ /* implicit */ Value(int i) : Value(NumberKind) {
+ data_.number = i;
+ }
+
+ /// Moves a Symbol, String, or Object rvalue into a new JS value.
+ template
+ /* implicit */ Value(T&& other) : Value(kindOf(other)) {
+ static_assert(
+ std::is_base_of::value ||
+ std::is_base_of::value ||
+ std::is_base_of