react-native-windows 0.76.3 → 0.77.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.flowconfig +5 -1
- package/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts +1 -0
- package/Libraries/ActionSheetIOS/ActionSheetIOS.js +13 -0
- package/Libraries/Animated/AnimatedEvent.js +1 -1
- package/Libraries/Animated/AnimatedImplementation.js +2 -2
- package/Libraries/Animated/NativeAnimatedAllowlist.js +20 -9
- package/Libraries/Animated/animations/Animation.js +60 -25
- package/Libraries/Animated/animations/DecayAnimation.js +26 -38
- package/Libraries/Animated/animations/SpringAnimation.js +33 -39
- package/Libraries/Animated/animations/TimingAnimation.js +34 -42
- package/Libraries/Animated/components/AnimatedFlatList.js +1 -1
- package/Libraries/Animated/components/AnimatedSectionList.js +3 -1
- package/Libraries/Animated/createAnimatedComponent.js +60 -33
- package/Libraries/Animated/nodes/AnimatedColor.js +1 -1
- package/Libraries/Animated/nodes/AnimatedInterpolation.js +1 -1
- package/Libraries/Animated/nodes/AnimatedNode.js +39 -45
- package/Libraries/Animated/nodes/AnimatedObject.js +13 -3
- package/Libraries/Animated/nodes/AnimatedProps.js +104 -46
- package/Libraries/Animated/nodes/AnimatedStyle.js +116 -39
- package/Libraries/Animated/nodes/AnimatedTransform.js +56 -23
- package/Libraries/Animated/nodes/AnimatedValue.js +1 -1
- package/Libraries/Animated/nodes/AnimatedWithChildren.js +1 -3
- package/Libraries/Animated/useAnimatedProps.js +41 -35
- package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts +19 -3
- package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +77 -5
- package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.windows.js +82 -5
- package/Libraries/Components/ActivityIndicator/ActivityIndicator.js +4 -4
- package/Libraries/Components/Button.js +9 -4
- package/Libraries/Components/Button.windows.js +19 -5
- package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.js +3 -1
- package/Libraries/Components/Glyph/Glyph.js +2 -1
- package/Libraries/Components/Keyboard/KeyboardAvoidingView.js +7 -0
- package/Libraries/Components/Popup/PopupNativeComponent.js +0 -1
- package/Libraries/Components/Pressable/Pressable.js +4 -4
- package/Libraries/Components/Pressable/Pressable.windows.js +10 -4
- package/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +13 -7
- package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +3 -2
- package/Libraries/Components/SafeAreaView/SafeAreaView.js +4 -4
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +0 -1
- package/Libraries/Components/ScrollView/ScrollView.js +49 -88
- package/Libraries/Components/ScrollView/ScrollViewCommands.js +1 -1
- package/Libraries/Components/ScrollView/ScrollViewContext.js +2 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +0 -2
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.windows.js +0 -5
- package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +8 -9
- package/Libraries/Components/Switch/Switch.js +8 -6
- package/Libraries/Components/Switch/Switch.windows.js +8 -6
- package/Libraries/Components/TextInput/InputAccessoryView.js +1 -1
- package/Libraries/Components/TextInput/RCTMultilineTextInputNativeComponent.js +4 -4
- package/Libraries/Components/TextInput/RCTSingelineTextInputNativeComponent.js +6 -4
- package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +2 -1
- package/Libraries/Components/TextInput/TextInput.d.ts +27 -4
- package/Libraries/Components/TextInput/TextInput.flow.js +36 -19
- package/Libraries/Components/TextInput/TextInput.js +37 -13
- package/Libraries/Components/TextInput/TextInput.windows.js +47 -16
- package/Libraries/Components/TextInput/TextInputState.js +11 -13
- package/Libraries/Components/TextInput/TextInputState.windows.js +11 -13
- package/Libraries/Components/Touchable/BoundingDimensions.js +11 -3
- package/Libraries/Components/Touchable/Position.js +7 -2
- package/Libraries/Components/Touchable/Touchable.js +4 -0
- package/Libraries/Components/Touchable/Touchable.windows.js +4 -0
- package/Libraries/Components/Touchable/TouchableBounce.js +6 -2
- package/Libraries/Components/Touchable/TouchableBounce.windows.js +227 -0
- package/Libraries/Components/Touchable/TouchableHighlight.js +5 -5
- package/Libraries/Components/Touchable/TouchableHighlight.windows.js +5 -5
- package/Libraries/Components/Touchable/TouchableNativeFeedback.windows.js +371 -0
- package/Libraries/Components/Touchable/TouchableOpacity.js +6 -5
- package/Libraries/Components/Touchable/TouchableOpacity.windows.js +11 -5
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +1 -2
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +9 -3
- package/Libraries/Components/View/ReactNativeStyleAttributes.js +6 -1
- package/Libraries/Components/View/View.js +4 -4
- package/Libraries/Components/View/View.windows.js +12 -5
- package/Libraries/Components/View/ViewAccessibility.d.ts +10 -0
- package/Libraries/Components/View/ViewAccessibility.windows.js +2 -0
- package/Libraries/Components/View/ViewNativeComponent.js +6 -98
- package/Libraries/Components/View/ViewPropTypes.d.ts +7 -0
- package/Libraries/Components/View/ViewPropTypes.js +0 -3
- package/Libraries/Components/View/ViewPropTypes.windows.js +2 -3
- package/Libraries/Core/ExceptionsManager.js +50 -29
- package/Libraries/Core/ReactNativeVersion.js +3 -3
- package/Libraries/Core/__mocks__/NativeExceptionsManager.js +0 -1
- package/Libraries/Core/setUpBatchedBridge.js +1 -10
- package/Libraries/Core/setUpDeveloperTools.js +1 -5
- package/Libraries/Core/setUpErrorHandling.js +20 -18
- package/Libraries/Core/setUpReactDevTools.js +107 -8
- package/Libraries/Core/setUpSegmentFetcher.js +1 -0
- package/Libraries/Core/setUpTimers.js +21 -18
- package/Libraries/Debugging/DebuggingOverlay.js +4 -5
- package/Libraries/Image/AssetSourceResolver.js +12 -1
- package/Libraries/Image/AssetSourceResolver.windows.js +12 -1
- package/Libraries/Image/Image.android.js +1 -5
- package/Libraries/Image/Image.d.ts +20 -29
- package/Libraries/Image/Image.ios.js +0 -2
- package/Libraries/Image/Image.windows.js +5 -1
- package/Libraries/Image/ImageBackground.js +2 -5
- package/Libraries/Image/ImageProps.js +7 -6
- package/Libraries/Image/ImageResizeMode.d.ts +8 -1
- package/Libraries/Image/ImageResizeMode.js +4 -1
- package/Libraries/Image/ImageSource.d.ts +0 -2
- package/Libraries/Image/ImageSource.js +0 -2
- package/Libraries/Image/ImageTypes.flow.js +11 -9
- package/Libraries/Image/ImageUtils.js +6 -3
- package/Libraries/Image/ImageViewNativeComponent.js +5 -3
- package/Libraries/Inspector/Inspector.js +1 -0
- package/Libraries/Inspector/NetworkOverlay.js +4 -0
- package/Libraries/Inspector/ReactDevToolsOverlay.js +8 -14
- package/Libraries/Inspector/getInspectorDataForViewAtPoint.js +3 -5
- package/Libraries/Interaction/InteractionManager.js +6 -1
- package/Libraries/Interaction/InteractionManagerStub.js +176 -0
- package/Libraries/Interaction/TouchHistoryMath.js +22 -19
- package/Libraries/JSInspector/NetworkAgent.js +1 -1
- package/Libraries/Lists/FlatList.d.ts +1 -2
- package/Libraries/Lists/FlatList.js +2 -2
- package/Libraries/Lists/SectionListModern.js +7 -7
- package/Libraries/Lists/__flowtests__/FlatList-flowtest.js +2 -2
- package/Libraries/Lists/__flowtests__/SectionList-flowtest.js +1 -1
- package/Libraries/LogBox/Data/LogBoxData.js +3 -3
- package/Libraries/LogBox/LogBox.js +18 -5
- package/Libraries/LogBox/LogBoxInspectorContainer.js +1 -1
- package/Libraries/LogBox/LogBoxNotificationContainer.js +2 -2
- package/Libraries/LogBox/UI/AnsiHighlight.js +26 -17
- package/Libraries/LogBox/UI/LogBoxInspectorCodeFrame.js +6 -1
- package/Libraries/LogBox/UI/LogBoxInspectorCodeFrame.windows.js +6 -1
- package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +1 -1
- package/Libraries/LogBox/UI/LogBoxInspectorHeader.windows.js +1 -1
- package/Libraries/LogBox/UI/LogBoxInspectorStackFrames.js +1 -1
- package/Libraries/LogBox/UI/LogBoxMessage.js +2 -2
- package/Libraries/Modal/Modal.d.ts +12 -0
- package/Libraries/Modal/Modal.js +31 -4
- package/Libraries/Modal/Modal.windows.js +18 -0
- package/Libraries/NativeComponent/BaseViewConfig.android.js +72 -1
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +2 -1
- package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -11
- package/Libraries/NativeComponent/NativeComponentRegistry.js +3 -3
- package/Libraries/NativeComponent/StaticViewConfigValidator.js +0 -1
- package/Libraries/Network/FormData.js +11 -3
- package/Libraries/Network/XHRInterceptor.js +63 -14
- package/Libraries/Network/XMLHttpRequest.js +26 -1
- package/Libraries/NewAppScreen/components/HermesBadge.js +1 -1
- package/Libraries/PermissionsAndroid/PermissionsAndroid.d.ts +49 -2
- package/Libraries/PermissionsAndroid/PermissionsAndroid.js +4 -4
- package/Libraries/Pressability/HoverState.js +2 -0
- package/Libraries/Pressability/Pressability.js +2 -3
- package/Libraries/Pressability/Pressability.windows.js +2 -3
- package/Libraries/Pressability/usePressability.js +4 -1
- package/Libraries/ReactNative/AppContainer.js +1 -1
- package/Libraries/ReactNative/AppRegistry.js +1 -11
- package/Libraries/ReactNative/DisplayMode.js +1 -1
- package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +2 -3
- package/Libraries/ReactNative/RendererImplementation.js +18 -17
- package/Libraries/ReactNative/getCachedComponentWithDebugName.js +1 -3
- package/Libraries/ReactNative/renderApplication.js +9 -8
- package/Libraries/ReactNative/requireNativeComponent.js +5 -2
- package/Libraries/Renderer/shims/ReactFabric.js +3 -3
- package/Libraries/Renderer/shims/ReactFeatureFlags.js +2 -2
- package/Libraries/Renderer/shims/ReactNative.js +3 -3
- package/Libraries/Renderer/shims/ReactNativeTypes.js +22 -35
- package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +5 -6
- package/Libraries/Renderer/shims/createReactNativeComponentClass.js +2 -2
- package/Libraries/StyleSheet/StyleSheet.js +7 -1
- package/Libraries/StyleSheet/StyleSheetTypes.d.ts +13 -2
- package/Libraries/StyleSheet/StyleSheetTypes.js +24 -6
- package/Libraries/StyleSheet/processBackgroundImage.js +87 -110
- package/Libraries/StyleSheet/processTransform.js +3 -34
- package/Libraries/Text/Text.js +248 -249
- package/Libraries/Text/Text.windows.js +298 -292
- package/Libraries/Text/TextNativeComponent.js +0 -1
- package/Libraries/Text/TextProps.windows.js +2 -0
- package/Libraries/TurboModule/TurboModuleRegistry.js +5 -5
- package/Libraries/Types/CoreEventTypes.d.ts +3 -10
- package/Libraries/Types/CoreEventTypes.js +4 -6
- package/Libraries/Types/CoreEventTypes.windows.js +4 -6
- package/Libraries/Utilities/Appearance.js +3 -1
- package/Libraries/Utilities/BackHandler.android.js +6 -18
- package/Libraries/Utilities/BackHandler.d.ts +0 -4
- package/Libraries/Utilities/BackHandler.ios.js +0 -7
- package/Libraries/Utilities/BackHandler.windows.js +6 -18
- package/Libraries/Utilities/HMRClient.js +3 -4
- package/Libraries/Utilities/Platform.flow.js +2 -2
- package/Libraries/Utilities/Platform.flow.windows.js +3 -2
- package/Libraries/Utilities/__mocks__/BackHandler.js +3 -8
- package/Libraries/Utilities/codegenNativeComponent.js +1 -1
- package/Libraries/Utilities/useMergeRefs.js +26 -7
- package/Libraries/WebSocket/WebSocketEvent.js +4 -1
- package/Libraries/WebSocket/WebSocketInterceptor.js +31 -13
- package/Libraries/__flowtests__/ReactNativeTypes-flowtest.js +6 -5
- package/Libraries/promiseRejectionTrackingOptions.js +1 -1
- package/Microsoft.ReactNative/AsynchronousEventBeat.cpp +9 -8
- package/Microsoft.ReactNative/AsynchronousEventBeat.h +5 -5
- package/Microsoft.ReactNative/FBReactNativeSpec/FBReactNativeSpecJSI.h +5 -0
- package/Microsoft.ReactNative/Fabric/AbiComponentDescriptor.cpp +2 -2
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +197 -18
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +19 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +13 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +6 -8
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +2 -2
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +3 -2
- package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +24 -0
- package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +5 -0
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +12 -12
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +4 -4
- package/Microsoft.ReactNative/Fabric/ImageRequest.cpp +4 -8
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +16 -15
- package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.cpp +15 -0
- package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.h +9 -0
- package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +20 -1
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +11 -6
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -1
- package/Microsoft.ReactNative/SynchronousEventBeat.cpp +14 -4
- package/Microsoft.ReactNative/SynchronousEventBeat.h +4 -2
- package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +78 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.h +51 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +48 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.cpp +41 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.h +127 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.inc +125 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +16 -0
- package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_win.cpp +23 -0
- package/Microsoft.ReactNative.Cxx/JSI/decorator.h +834 -0
- package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +117 -0
- package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +366 -0
- package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +560 -0
- package/Microsoft.ReactNative.Cxx/JSI/jsi.h +1611 -0
- package/Microsoft.ReactNative.Cxx/JSI/threadsafe.h +79 -0
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +7 -11
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems.filters +1 -1
- package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +2878 -0
- package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +36 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/CallInvoker.h +64 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/SchedulerPriority.h +22 -0
- package/{ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core → Microsoft.ReactNative.Cxx}/ReactCommon/TurboModule.cpp +63 -63
- package/Microsoft.ReactNative.Cxx/ReactCommon/TurboModule.h +165 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/TurboModuleUtils.cpp +105 -0
- package/{ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core → Microsoft.ReactNative.Cxx}/ReactCommon/TurboModuleUtils.h +57 -58
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/AString.h +42 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Array.h +151 -0
- package/{ReactCommon/TEMP_UntilReactCommonUpdate → Microsoft.ReactNative.Cxx/ReactCommon}/react/bridging/Base.h +177 -154
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Bool.h +25 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Bridging.h +21 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/CallbackWrapper.h +67 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Class.h +90 -0
- package/{ReactCommon/TEMP_UntilReactCommonUpdate → Microsoft.ReactNative.Cxx/ReactCommon}/react/bridging/Convert.h +170 -172
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Error.h +51 -0
- package/{ReactCommon/TEMP_UntilReactCommonUpdate → Microsoft.ReactNative.Cxx/ReactCommon}/react/bridging/EventEmitter.h +134 -136
- package/{ReactCommon/TEMP_UntilReactCommonUpdate → Microsoft.ReactNative.Cxx/ReactCommon}/react/bridging/Function.h +283 -283
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/LongLivedObject.cpp +63 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/LongLivedObject.h +61 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Object.h +93 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Promise.h +104 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Value.h +107 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/debug/flags.h +22 -0
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/debug/react_native_assert.h +72 -0
- package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +553 -0
- package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +167 -0
- package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +186 -0
- package/Microsoft.ReactNative.Cxx/stubs/glog/logging.h +82 -0
- package/PropertySheets/Bundle.Common.targets +1 -1
- package/PropertySheets/Bundle.props +3 -0
- package/PropertySheets/Generated/PackageVersion.g.props +4 -4
- package/PropertySheets/ManagedCodeGen/Microsoft.ReactNative.Managed.CodeGen.targets +1 -1
- package/PropertySheets/OutputMSBuildProperties.targets +3 -1
- package/PropertySheets/React.Cpp.props +6 -0
- package/ReactCommon/ReactCommon.vcxproj +5 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +2 -3
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +61 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.h +26 -23
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +150 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +252 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/accessibilityPropsConversions.h +795 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/runtimescheduler/SchedulerPriorityUtils.h +59 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +227 -74
- package/Scripts/Microsoft.ReactNative.Managed.CodeGen.targets +1 -1
- package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +97 -62
- package/Shared/InspectorPackagerConnection.cpp +3 -6
- package/Shared/InspectorPackagerConnection.h +2 -2
- package/Shared/InstanceManager.h +1 -1
- package/Shared/OInstance.h +1 -1
- package/Shared/Shared.vcxitems +17 -2
- package/Shared/Shared.vcxitems.filters +3 -1
- package/Shared/TurboModuleManager.cpp +29 -4
- package/codegen/NativeAccessibilityInfoSpec.g.h +27 -9
- package/codegen/NativeAccessibilityManagerSpec.g.h +19 -13
- package/codegen/NativeActionSheetManagerSpec.g.h +4 -0
- package/codegen/NativeExceptionsManagerSpec.g.h +1 -7
- package/codegen/NativeIntersectionObserverSpec.g.h +2 -0
- package/codegen/NativePerformanceSpec.g.h +127 -3
- package/codegen/NativeReactDevToolsRuntimeSettingsModuleSpec.g.h +67 -0
- package/codegen/NativeReactDevToolsSettingsManagerSpec.g.h +41 -0
- package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +125 -137
- package/codegen/react/components/rnwcore/ComponentDescriptors.h +0 -1
- package/codegen/react/components/rnwcore/Props.cpp +1 -0
- package/codegen/react/components/rnwcore/Props.h +1 -0
- package/codegen/react/components/rnwcore/ShadowNodes.cpp +0 -1
- package/codegen/react/components/rnwcore/ShadowNodes.h +0 -11
- package/codegen/react/components/rnwcore/States.h +0 -12
- package/codegen/rnwcoreJSI-generated.cpp +219 -186
- package/codegen/rnwcoreJSI.h +942 -511
- package/index.js +10 -3
- package/index.windows.js +10 -3
- package/jest/setup.js +36 -1
- package/just-task.js +15 -0
- package/package.json +22 -22
- package/src/private/animated/NativeAnimatedHelper.js +18 -16
- package/src/private/animated/useAnimatedPropsMemo.js +356 -0
- package/src/private/components/HScrollViewNativeComponents.js +1 -27
- package/src/private/components/SafeAreaView_INTERNAL_DO_NOT_USE.js +11 -8
- package/src/private/components/VScrollViewNativeComponents.js +2 -25
- package/src/private/debugging/ReactDevToolsSettingsManager.android.js +20 -0
- package/src/private/debugging/ReactDevToolsSettingsManager.ios.js +30 -0
- package/src/private/debugging/ReactDevToolsSettingsManager.windows.js +20 -0
- package/src/private/{fusebox → debugging}/setUpFuseboxReactDevToolsDispatcher.js +6 -0
- package/src/private/devmenu/DevMenu.d.ts +20 -0
- package/src/private/devmenu/DevMenu.js +31 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +95 -86
- package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +8 -2
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +17 -19
- package/src/private/fusebox/specs/NativeReactDevToolsRuntimeSettingsModule.js +34 -0
- package/src/private/setup/setUpDOM.js +14 -6
- package/src/private/setup/setUpMutationObserver.js +5 -0
- package/src/private/specs/components/AndroidHorizontalScrollContentViewNativeComponent.js +1 -0
- package/src/private/specs/components/RCTModalHostViewNativeComponent.js +8 -0
- package/src/private/specs/modules/NativeAccessibilityInfo.js +9 -0
- package/src/private/specs/modules/NativeAccessibilityManager.js +4 -0
- package/src/private/specs/modules/NativeActionSheetManager.js +2 -0
- package/src/private/specs/modules/NativeAppearance.js +4 -10
- package/src/private/specs/modules/NativeExceptionsManager.js +0 -12
- package/src/private/specs/modules/{NativeDevToolsSettingsManager.js → NativeReactDevToolsSettingsManager.js} +3 -5
- package/src/private/webapis/dom/geometry/DOMRect.js +2 -2
- package/src/private/webapis/dom/geometry/DOMRectReadOnly.js +2 -2
- package/src/private/webapis/dom/nodes/ReactNativeElement.js +2 -3
- package/src/private/webapis/intersectionobserver/IntersectionObserver.js +102 -11
- package/src/private/webapis/intersectionobserver/IntersectionObserverEntry.js +26 -0
- package/src/private/webapis/intersectionobserver/IntersectionObserverManager.js +1 -0
- package/src/private/webapis/intersectionobserver/specs/NativeIntersectionObserver.js +1 -0
- package/src/private/webapis/intersectionobserver/specs/__mocks__/NativeIntersectionObserver.js +9 -0
- package/src/private/webapis/performance/EventTiming.js +13 -8
- package/src/private/webapis/performance/Performance.js +66 -73
- package/src/private/webapis/performance/PerformanceEntry.js +2 -5
- package/src/private/webapis/performance/PerformanceObserver.js +65 -164
- package/src/private/webapis/performance/RawPerformanceEntry.js +1 -1
- package/src/private/webapis/performance/UserTiming.js +11 -7
- package/src/private/webapis/performance/Utilities.js +18 -0
- package/src/private/webapis/performance/specs/NativePerformance.js +71 -2
- package/src/private/webapis/performance/specs/__mocks__/NativePerformanceMock.js +267 -0
- package/templates/cpp-lib/template.config.js +13 -7
- package/templates/templateUtils.js +10 -0
- package/types/index.d.ts +1 -1
- package/types/public/ReactNativeTypes.d.ts +4 -8
- package/Libraries/DevToolsSettings/DevToolsSettingsManager.android.js +0 -35
- package/Libraries/DevToolsSettings/DevToolsSettingsManager.d.ts +0 -20
- package/Libraries/DevToolsSettings/DevToolsSettingsManager.ios.js +0 -49
- package/Libraries/DevToolsSettings/DevToolsSettingsManager.windows.js +0 -35
- package/Libraries/DevToolsSettings/NativeDevToolsSettingsManager.js +0 -13
- package/Libraries/ReactNative/ReactFabricInternals.js +0 -17
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/CallbackWrapper.h +0 -101
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/scrollview/ScrollViewProps.cpp +0 -569
- package/codegen/NativeDevToolsSettingsManagerSpec.g.h +0 -53
- package/codegen/NativePerformanceObserverSpec.g.h +0 -131
- package/src/private/components/useSyncOnScroll.js +0 -48
- package/src/private/webapis/performance/specs/NativePerformanceObserver.js +0 -61
- package/src/private/webapis/performance/specs/__mocks__/NativePerformance.js +0 -67
- package/src/private/webapis/performance/specs/__mocks__/NativePerformanceObserver.js +0 -127
- package/types/experimental.d.ts +0 -59
- /package/src/private/{fusebox → debugging}/FuseboxSessionObserver.js +0 -0
|
@@ -0,0 +1,2878 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#define NAPI_EXPERIMENTAL
|
|
5
|
+
|
|
6
|
+
#include "NodeApiJsiRuntime.h"
|
|
7
|
+
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
#include <array>
|
|
10
|
+
#include <optional>
|
|
11
|
+
#include <sstream>
|
|
12
|
+
#include <string_view>
|
|
13
|
+
#include <unordered_map>
|
|
14
|
+
#include <unordered_set>
|
|
15
|
+
|
|
16
|
+
// JSI version defines set of features available in the API.
|
|
17
|
+
// Each significant API change must be under a new version.
|
|
18
|
+
// These macros must be defined in jsi.h, but define them here too
|
|
19
|
+
// in case if this code is used with unmodified jsi.h.
|
|
20
|
+
#ifndef JSI_VERSION
|
|
21
|
+
#define JSI_VERSION 10
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
#ifndef JSI_NO_CONST_3
|
|
25
|
+
#if JSI_VERSION >= 3
|
|
26
|
+
#define JSI_NO_CONST_3
|
|
27
|
+
#else
|
|
28
|
+
#define JSI_NO_CONST_3 const
|
|
29
|
+
#endif
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#ifndef JSI_CONST_10
|
|
33
|
+
#if JSI_VERSION >= 10
|
|
34
|
+
#define JSI_CONST_10 const
|
|
35
|
+
#else
|
|
36
|
+
#define JSI_CONST_10
|
|
37
|
+
#endif
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
using namespace facebook;
|
|
41
|
+
using namespace std::string_view_literals;
|
|
42
|
+
|
|
43
|
+
// We use macros to report errors.
|
|
44
|
+
// Macros provide more flexibility to show assert and provide failure context.
|
|
45
|
+
|
|
46
|
+
// Check condition and crash process if it fails.
|
|
47
|
+
#define CHECK_ELSE_CRASH(condition, message) \
|
|
48
|
+
do { \
|
|
49
|
+
if (!(condition)) { \
|
|
50
|
+
assert(false && "Failed: " #condition && (message)); \
|
|
51
|
+
*((int *)0) = 1; \
|
|
52
|
+
} \
|
|
53
|
+
} while (false)
|
|
54
|
+
|
|
55
|
+
// Check condition and throw native exception if it fails.
|
|
56
|
+
#define CHECK_ELSE_THROW(condition, message) \
|
|
57
|
+
do { \
|
|
58
|
+
if (!(condition)) { \
|
|
59
|
+
throwNativeException(message); \
|
|
60
|
+
} \
|
|
61
|
+
} while (false)
|
|
62
|
+
|
|
63
|
+
// Check NAPI result and and throw JS exception if it is not napi_ok.
|
|
64
|
+
#define CHECK_NAPI(...) \
|
|
65
|
+
do { \
|
|
66
|
+
napi_status temp_error_code_ = (__VA_ARGS__); \
|
|
67
|
+
if (temp_error_code_ != napi_status::napi_ok) { \
|
|
68
|
+
runtime.throwJSException(temp_error_code_); \
|
|
69
|
+
} \
|
|
70
|
+
} while (false)
|
|
71
|
+
|
|
72
|
+
// Check NAPI result and and crash if it is not napi_ok.
|
|
73
|
+
#define CHECK_NAPI_ELSE_CRASH(expression) \
|
|
74
|
+
do { \
|
|
75
|
+
napi_status temp_error_code_ = (expression); \
|
|
76
|
+
if (temp_error_code_ != napi_status::napi_ok) { \
|
|
77
|
+
CHECK_ELSE_CRASH(false, "Failed: " #expression); \
|
|
78
|
+
} \
|
|
79
|
+
} while (false)
|
|
80
|
+
|
|
81
|
+
// Check NAPI result and return it when it is an error.
|
|
82
|
+
#define NAPI_CALL(expression) \
|
|
83
|
+
do { \
|
|
84
|
+
napi_status temp_error_code_ = (expression); \
|
|
85
|
+
if (temp_error_code_ != napi_status::napi_ok) { \
|
|
86
|
+
return temp_error_code_; \
|
|
87
|
+
} \
|
|
88
|
+
} while (false)
|
|
89
|
+
|
|
90
|
+
#ifdef __cpp_lib_span
|
|
91
|
+
#include <span>
|
|
92
|
+
#endif // __cpp_lib_span
|
|
93
|
+
|
|
94
|
+
namespace Microsoft::NodeApiJsi {
|
|
95
|
+
|
|
96
|
+
namespace {
|
|
97
|
+
|
|
98
|
+
#ifdef __cpp_lib_span
|
|
99
|
+
using std::span;
|
|
100
|
+
#else
|
|
101
|
+
/**
|
|
102
|
+
* @brief A span of values that can be used to pass arguments to a function.
|
|
103
|
+
*
|
|
104
|
+
* This should be replaced with std::span once C++20 is supported.
|
|
105
|
+
*/
|
|
106
|
+
template <typename T>
|
|
107
|
+
class span {
|
|
108
|
+
public:
|
|
109
|
+
constexpr span() noexcept : data_{nullptr}, size_{0} {}
|
|
110
|
+
constexpr span(T *data, size_t size) noexcept : data_{data}, size_{size} {}
|
|
111
|
+
template <std::size_t N>
|
|
112
|
+
constexpr span(T (&arr)[N]) noexcept : data_{arr}, size_{N} {}
|
|
113
|
+
|
|
114
|
+
[[nodiscard]] constexpr T *data() const noexcept {
|
|
115
|
+
return data_;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
[[nodiscard]] constexpr size_t size() const noexcept {
|
|
119
|
+
return size_;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
[[nodiscard]] constexpr T *begin() const noexcept {
|
|
123
|
+
return data_;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
[[nodiscard]] constexpr T *end() const noexcept {
|
|
127
|
+
return *(data_ + size_);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const T &operator[](size_t index) const noexcept {
|
|
131
|
+
return *(data_ + index);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private:
|
|
135
|
+
T *data_;
|
|
136
|
+
size_t size_;
|
|
137
|
+
};
|
|
138
|
+
#endif // __cpp_lib_span
|
|
139
|
+
|
|
140
|
+
// To be used as a key in a unordered_map.
|
|
141
|
+
class StringKey {
|
|
142
|
+
public:
|
|
143
|
+
explicit StringKey(std::string &&string) noexcept;
|
|
144
|
+
explicit StringKey(std::string_view view) noexcept;
|
|
145
|
+
explicit StringKey(const char *data, size_t length) noexcept;
|
|
146
|
+
StringKey(StringKey &&other) noexcept;
|
|
147
|
+
StringKey &operator=(StringKey &&other) noexcept;
|
|
148
|
+
StringKey(const StringKey &other) = delete;
|
|
149
|
+
StringKey &operator=(const StringKey &other) = delete;
|
|
150
|
+
~StringKey();
|
|
151
|
+
|
|
152
|
+
std::string_view getStringView() const;
|
|
153
|
+
bool equalTo(const StringKey &other) const;
|
|
154
|
+
size_t hash() const;
|
|
155
|
+
|
|
156
|
+
struct Hash {
|
|
157
|
+
size_t operator()(const StringKey &key) const;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
struct EqualTo {
|
|
161
|
+
bool operator()(const StringKey &left, const StringKey &right) const;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
private:
|
|
165
|
+
enum class Type {
|
|
166
|
+
String,
|
|
167
|
+
View,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
private:
|
|
171
|
+
union {
|
|
172
|
+
std::string string_;
|
|
173
|
+
std::string_view view_;
|
|
174
|
+
};
|
|
175
|
+
Type type_{Type::String};
|
|
176
|
+
size_t hash_;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Implementation of N-API JSI Runtime
|
|
180
|
+
class NodeApiJsiRuntime : public jsi::Runtime {
|
|
181
|
+
public:
|
|
182
|
+
NodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept;
|
|
183
|
+
~NodeApiJsiRuntime() override;
|
|
184
|
+
|
|
185
|
+
jsi::Value evaluateJavaScript(const std::shared_ptr<const jsi::Buffer> &buffer, const std::string &sourceURL)
|
|
186
|
+
override;
|
|
187
|
+
std::shared_ptr<const jsi::PreparedJavaScript> prepareJavaScript(
|
|
188
|
+
const std::shared_ptr<const jsi::Buffer> &buffer,
|
|
189
|
+
std::string sourceURL) override;
|
|
190
|
+
jsi::Value evaluatePreparedJavaScript(const std::shared_ptr<const jsi::PreparedJavaScript> &js) override;
|
|
191
|
+
#if JSI_VERSION >= 4
|
|
192
|
+
bool drainMicrotasks(int maxMicrotasksHint = -1) override;
|
|
193
|
+
#endif
|
|
194
|
+
jsi::Object global() override;
|
|
195
|
+
std::string description() override;
|
|
196
|
+
bool isInspectable() override;
|
|
197
|
+
|
|
198
|
+
protected:
|
|
199
|
+
PointerValue *cloneSymbol(const PointerValue *pointerValue) override;
|
|
200
|
+
#if JSI_VERSION >= 6
|
|
201
|
+
PointerValue *cloneBigInt(const PointerValue *pointerValue) override;
|
|
202
|
+
#endif
|
|
203
|
+
PointerValue *cloneString(const PointerValue *pointerValue) override;
|
|
204
|
+
PointerValue *cloneObject(const PointerValue *pointerValue) override;
|
|
205
|
+
PointerValue *clonePropNameID(const PointerValue *pointerValue) override;
|
|
206
|
+
|
|
207
|
+
jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override;
|
|
208
|
+
jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override;
|
|
209
|
+
jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override;
|
|
210
|
+
#if JSI_VERSION >= 5
|
|
211
|
+
jsi::PropNameID createPropNameIDFromSymbol(const jsi::Symbol &sym) override;
|
|
212
|
+
#endif
|
|
213
|
+
std::string utf8(const jsi::PropNameID &id) override;
|
|
214
|
+
bool compare(const jsi::PropNameID &lhs, const jsi::PropNameID &rhs) override;
|
|
215
|
+
|
|
216
|
+
std::string symbolToString(const jsi::Symbol &s) override;
|
|
217
|
+
|
|
218
|
+
#if JSI_VERSION >= 8
|
|
219
|
+
jsi::BigInt createBigIntFromInt64(int64_t value) override;
|
|
220
|
+
jsi::BigInt createBigIntFromUint64(uint64_t value) override;
|
|
221
|
+
bool bigintIsInt64(const jsi::BigInt &value) override;
|
|
222
|
+
bool bigintIsUint64(const jsi::BigInt &value) override;
|
|
223
|
+
uint64_t truncate(const jsi::BigInt &value) override;
|
|
224
|
+
jsi::String bigintToString(const jsi::BigInt &value, int radix) override;
|
|
225
|
+
#endif
|
|
226
|
+
|
|
227
|
+
jsi::String createStringFromAscii(const char *str, size_t length) override;
|
|
228
|
+
jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override;
|
|
229
|
+
std::string utf8(const jsi::String &str) override;
|
|
230
|
+
|
|
231
|
+
jsi::Object createObject() override;
|
|
232
|
+
jsi::Object createObject(std::shared_ptr<jsi::HostObject> ho) override;
|
|
233
|
+
std::shared_ptr<jsi::HostObject> getHostObject(const jsi::Object &) override;
|
|
234
|
+
jsi::HostFunctionType &getHostFunction(const jsi::Function &) override;
|
|
235
|
+
|
|
236
|
+
#if JSI_VERSION >= 7
|
|
237
|
+
bool hasNativeState(const jsi::Object &value) override;
|
|
238
|
+
std::shared_ptr<jsi::NativeState> getNativeState(const jsi::Object &value) override;
|
|
239
|
+
void setNativeState(const jsi::Object &value, std::shared_ptr<jsi::NativeState> state) override;
|
|
240
|
+
#endif
|
|
241
|
+
|
|
242
|
+
jsi::Value getProperty(const jsi::Object &obj, const jsi::PropNameID &name) override;
|
|
243
|
+
jsi::Value getProperty(const jsi::Object &obj, const jsi::String &name) override;
|
|
244
|
+
bool hasProperty(const jsi::Object &obj, const jsi::PropNameID &name) override;
|
|
245
|
+
bool hasProperty(const jsi::Object &obj, const jsi::String &name) override;
|
|
246
|
+
void setPropertyValue(JSI_CONST_10 jsi::Object &obj, const jsi::PropNameID &name, const jsi::Value &value) override;
|
|
247
|
+
void setPropertyValue(JSI_CONST_10 jsi::Object &obj, const jsi::String &name, const jsi::Value &value) override;
|
|
248
|
+
|
|
249
|
+
bool isArray(const jsi::Object &obj) const override;
|
|
250
|
+
bool isArrayBuffer(const jsi::Object &obj) const override;
|
|
251
|
+
bool isFunction(const jsi::Object &obj) const override;
|
|
252
|
+
bool isHostObject(const jsi::Object &obj) const override;
|
|
253
|
+
bool isHostFunction(const jsi::Function &func) const override;
|
|
254
|
+
jsi::Array getPropertyNames(const jsi::Object &obj) override;
|
|
255
|
+
|
|
256
|
+
jsi::WeakObject createWeakObject(const jsi::Object &obj) override;
|
|
257
|
+
jsi::Value lockWeakObject(JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObj) override;
|
|
258
|
+
|
|
259
|
+
jsi::Array createArray(size_t length) override;
|
|
260
|
+
#if JSI_VERSION >= 9
|
|
261
|
+
jsi::ArrayBuffer createArrayBuffer(std::shared_ptr<jsi::MutableBuffer> buffer);
|
|
262
|
+
#endif
|
|
263
|
+
size_t size(const jsi::Array &arr) override;
|
|
264
|
+
size_t size(const jsi::ArrayBuffer &arrBuf) override;
|
|
265
|
+
uint8_t *data(const jsi::ArrayBuffer &arrBuff) override;
|
|
266
|
+
jsi::Value getValueAtIndex(const jsi::Array &arr, size_t index) override;
|
|
267
|
+
void setValueAtIndexImpl(JSI_CONST_10 jsi::Array &arr, size_t index, const jsi::Value &value) override;
|
|
268
|
+
|
|
269
|
+
jsi::Function createFunctionFromHostFunction(
|
|
270
|
+
const jsi::PropNameID &name,
|
|
271
|
+
unsigned int paramCount,
|
|
272
|
+
jsi::HostFunctionType func) override;
|
|
273
|
+
jsi::Value call(const jsi::Function &func, const jsi::Value &jsThis, const jsi::Value *args, size_t count) override;
|
|
274
|
+
jsi::Value callAsConstructor(const jsi::Function &func, const jsi::Value *args, size_t count) override;
|
|
275
|
+
|
|
276
|
+
ScopeState *pushScope() override;
|
|
277
|
+
void popScope(ScopeState *) override;
|
|
278
|
+
|
|
279
|
+
bool strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const override;
|
|
280
|
+
#if JSI_VERSION >= 6
|
|
281
|
+
bool strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const override;
|
|
282
|
+
#endif
|
|
283
|
+
bool strictEquals(const jsi::String &a, const jsi::String &b) const override;
|
|
284
|
+
bool strictEquals(const jsi::Object &a, const jsi::Object &b) const override;
|
|
285
|
+
|
|
286
|
+
bool instanceOf(const jsi::Object &obj, const jsi::Function &func) override;
|
|
287
|
+
|
|
288
|
+
#if JSI_VERSION >= 11
|
|
289
|
+
void setExternalMemoryPressure(const jsi::Object &obj, size_t amount) override;
|
|
290
|
+
#endif
|
|
291
|
+
|
|
292
|
+
private:
|
|
293
|
+
// RAII class to open and close the environment scope.
|
|
294
|
+
class NodeApiScope {
|
|
295
|
+
public:
|
|
296
|
+
NodeApiScope(const NodeApiJsiRuntime &runtime) noexcept;
|
|
297
|
+
NodeApiScope(NodeApiJsiRuntime &runtime) noexcept;
|
|
298
|
+
~NodeApiScope() noexcept;
|
|
299
|
+
|
|
300
|
+
NodeApiScope(const NodeApiScope &) = delete;
|
|
301
|
+
NodeApiScope &operator=(const NodeApiScope &) = delete;
|
|
302
|
+
|
|
303
|
+
private:
|
|
304
|
+
NodeApiJsiRuntime &runtime_;
|
|
305
|
+
NodeApiEnvScope envScope_;
|
|
306
|
+
ScopeState *scopeState_{};
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// RAII class to open and close the environment scope.
|
|
310
|
+
class NodeApiPointerValueScope {
|
|
311
|
+
public:
|
|
312
|
+
NodeApiPointerValueScope(NodeApiJsiRuntime &runtime) noexcept;
|
|
313
|
+
~NodeApiPointerValueScope() noexcept;
|
|
314
|
+
|
|
315
|
+
NodeApiPointerValueScope(const NodeApiPointerValueScope &) = delete;
|
|
316
|
+
NodeApiPointerValueScope &operator=(const NodeApiPointerValueScope &) = delete;
|
|
317
|
+
|
|
318
|
+
private:
|
|
319
|
+
NodeApiJsiRuntime &runtime_;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
// Sets the variable in the constructor and then restores its value in the destructor.
|
|
323
|
+
template <typename T>
|
|
324
|
+
class AutoRestore {
|
|
325
|
+
public:
|
|
326
|
+
AutoRestore(T &varRef, T value);
|
|
327
|
+
~AutoRestore();
|
|
328
|
+
|
|
329
|
+
AutoRestore(const AutoRestore &) = delete;
|
|
330
|
+
AutoRestore &operator=(const AutoRestore &) = delete;
|
|
331
|
+
|
|
332
|
+
private:
|
|
333
|
+
T &varRef_;
|
|
334
|
+
T oldValue_;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
enum class NodeApiPointerValueKind {
|
|
338
|
+
Object,
|
|
339
|
+
WeakObject,
|
|
340
|
+
String,
|
|
341
|
+
StringPropNameID,
|
|
342
|
+
Symbol,
|
|
343
|
+
BigInt,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
class NodeApiRefCountedPointerValue;
|
|
347
|
+
|
|
348
|
+
// NodeApiPointerValue is used by jsi::Pointer derived classes.
|
|
349
|
+
struct NodeApiPointerValue : PointerValue {
|
|
350
|
+
virtual NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const = 0;
|
|
351
|
+
virtual napi_value getValue(NodeApiJsiRuntime &runtime) noexcept = 0;
|
|
352
|
+
virtual NodeApiPointerValueKind getKind() const noexcept = 0;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// NodeApiStackOnlyPointerValue helps to avoid memory allocation in some scenarios.
|
|
356
|
+
// It is used by the JsiValueView, JsiValueViewArgs, and PropNameIDView classes
|
|
357
|
+
// to keep temporary PointerValues on the call stack.
|
|
358
|
+
class NodeApiStackOnlyPointerValue final : public NodeApiPointerValue {
|
|
359
|
+
public:
|
|
360
|
+
NodeApiStackOnlyPointerValue(napi_value value, NodeApiPointerValueKind pointerKind) noexcept;
|
|
361
|
+
|
|
362
|
+
void invalidate() noexcept override;
|
|
363
|
+
NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const override;
|
|
364
|
+
napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
|
|
365
|
+
NodeApiPointerValueKind getKind() const noexcept override;
|
|
366
|
+
|
|
367
|
+
NodeApiStackOnlyPointerValue(const NodeApiStackOnlyPointerValue &) = delete;
|
|
368
|
+
NodeApiStackOnlyPointerValue &operator=(const NodeApiStackOnlyPointerValue &) = delete;
|
|
369
|
+
|
|
370
|
+
private:
|
|
371
|
+
napi_value value_{};
|
|
372
|
+
NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// NodeApiRefCountedPointerValue is a ref counted implementation of PointerValue that is allocated in the heap.
|
|
376
|
+
// It expects to have three different types of smart pointers:
|
|
377
|
+
// - jsi::Pointer derived classes uses clone() and invalidate() methods to increment and decrement the ref count.
|
|
378
|
+
// The invalidate() method can be called from any thread.
|
|
379
|
+
// - NodeApiStackValueHolder points to NodeApiRefCountedPointerValue when it has associated napi_value.
|
|
380
|
+
// - NodeApiRefHolder points to NodeApiRefCountedPointerValue when it has associated napi_ref.
|
|
381
|
+
//
|
|
382
|
+
// Using three types of smart pointers ensures that we always destroy napi_ref from the right thread.
|
|
383
|
+
// The invalidate() method can destroy NodeApiRefCountedPointerValue from a different thread only when there are
|
|
384
|
+
// no napi_value or napi_ref present in the class. Otherwise, the destruction will happen when we remove
|
|
385
|
+
// either napi_value or napi_ref reference.
|
|
386
|
+
//
|
|
387
|
+
// Some NodeApiRefCountedPointerValue are created with napi_value and may never get napi_ref.
|
|
388
|
+
// When stack scope is closed we see if there any jsi::Pointer references. If such references still exist, then
|
|
389
|
+
// we ensure that it has an associated napi_ref or we create one.
|
|
390
|
+
//
|
|
391
|
+
// In addition to the scope closure, there are two cases when we collect NodeApiRefCountedPointerValue
|
|
392
|
+
// without jsi::Pointer references:
|
|
393
|
+
// - When we grow the NodeApiJsiRuntime::stackValues_ vector and we reached current capacity.
|
|
394
|
+
// - When we grow the NodeApiJsiRuntime::refs_ vector and we reached current capacity.
|
|
395
|
+
class NodeApiRefCountedPointerValue final : public NodeApiPointerValue {
|
|
396
|
+
public:
|
|
397
|
+
// Creates new NodeApiRefCountedPointerValue and adds it to the NodeApiJsiRuntime::stackValues_. The ref count
|
|
398
|
+
// usually starts with 2: one for NodeApiJsiRuntime::stackValues_ reference and another for the targeting
|
|
399
|
+
// jsi::Pointer.
|
|
400
|
+
static NodeApiRefCountedPointerValue *make(
|
|
401
|
+
NodeApiJsiRuntime &runtime,
|
|
402
|
+
napi_value value,
|
|
403
|
+
NodeApiPointerValueKind pointerKind,
|
|
404
|
+
int32_t initialRefCount = 2);
|
|
405
|
+
|
|
406
|
+
// Creates new NodeApiRefCountedPointerValue and adds it to the NodeApiJsiRuntime::stackValues_. Then, it creates
|
|
407
|
+
// the napi_ref. The ref count usually starts with 2: one for NodeApiJsiRuntime::stackValues_ reference and another
|
|
408
|
+
// for the targeting NodeApiRefHolder.
|
|
409
|
+
static NodeApiRefCountedPointerValue *makeNodeApiRef(
|
|
410
|
+
NodeApiJsiRuntime &runtime,
|
|
411
|
+
napi_value value,
|
|
412
|
+
NodeApiPointerValueKind pointerKind,
|
|
413
|
+
int32_t initialRefCount = 2);
|
|
414
|
+
|
|
415
|
+
void invalidate() noexcept override;
|
|
416
|
+
NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const override;
|
|
417
|
+
napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
|
|
418
|
+
NodeApiPointerValueKind getKind() const noexcept override;
|
|
419
|
+
|
|
420
|
+
// Returns true if the ref count is bigger than if we would have only references for napi_value and napi_ref.
|
|
421
|
+
static bool usedByJsiPointer(NodeApiRefCountedPointerValue *ptr) noexcept;
|
|
422
|
+
|
|
423
|
+
// Remove napi_value field.
|
|
424
|
+
static void deleteStackValue(NodeApiRefCountedPointerValue *ptr) noexcept;
|
|
425
|
+
|
|
426
|
+
// Removes napi_value field and ensures existence of napi_ref field.
|
|
427
|
+
// Returns true if napi_ref was created and ref count did not change.
|
|
428
|
+
// Otherwise, the napi_ref was already there and the ref count was decremented.
|
|
429
|
+
void convertToNodeApiRef(NodeApiJsiRuntime &runtime) noexcept;
|
|
430
|
+
|
|
431
|
+
// Removes napi_ref pointer and decrements ref count. The napi_ref is not deleted.
|
|
432
|
+
// It is useful for napi_env shutdown when napi_env deletes napi_ref and we must not do it.
|
|
433
|
+
static void deleteNodeApiRef(NodeApiRefCountedPointerValue *ptr) noexcept;
|
|
434
|
+
|
|
435
|
+
// Deletes napi_ref, removes napi_ref pointer, and decrements ref count.
|
|
436
|
+
// This method must be used in all scenarios except for napi_env shutdown.
|
|
437
|
+
static void deleteNodeApiRef(NodeApiRefCountedPointerValue *ptr, NodeApiJsiRuntime &runtime) noexcept;
|
|
438
|
+
|
|
439
|
+
NodeApiRefCountedPointerValue(const NodeApiRefCountedPointerValue &) = delete;
|
|
440
|
+
NodeApiRefCountedPointerValue &operator=(const NodeApiRefCountedPointerValue &) = delete;
|
|
441
|
+
|
|
442
|
+
private:
|
|
443
|
+
NodeApiRefCountedPointerValue(
|
|
444
|
+
napi_value value,
|
|
445
|
+
NodeApiPointerValueKind pointerKind,
|
|
446
|
+
int32_t initialRefCount) noexcept;
|
|
447
|
+
|
|
448
|
+
void incRefCount() const noexcept;
|
|
449
|
+
|
|
450
|
+
// Decrements ref count. Delete this instance if ref count is zero.
|
|
451
|
+
void decRefCount() const noexcept;
|
|
452
|
+
|
|
453
|
+
NodeApiRefCountedPointerValue *createNodeApiRef(NodeApiJsiRuntime &runtime);
|
|
454
|
+
|
|
455
|
+
private:
|
|
456
|
+
napi_value value_{};
|
|
457
|
+
napi_ref ref_{};
|
|
458
|
+
mutable std::atomic<int32_t> refCount_{};
|
|
459
|
+
const NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
|
|
460
|
+
|
|
461
|
+
static constexpr char kPrimitivePropertyName[] = "X";
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
using NodeApiPointerValueDeleter = void(NodeApiRefCountedPointerValue *);
|
|
465
|
+
|
|
466
|
+
template <NodeApiPointerValueDeleter *deleter>
|
|
467
|
+
class NodeApiPointerValueHolder {
|
|
468
|
+
public:
|
|
469
|
+
NodeApiPointerValueHolder() = default;
|
|
470
|
+
explicit NodeApiPointerValueHolder(NodeApiRefCountedPointerValue *ptr) : ptr_(ptr) {}
|
|
471
|
+
|
|
472
|
+
NodeApiPointerValueHolder(NodeApiPointerValueHolder &&other) : ptr_(std::exchange(other.ptr_, nullptr)) {}
|
|
473
|
+
|
|
474
|
+
NodeApiPointerValueHolder &operator=(NodeApiPointerValueHolder &&other) {
|
|
475
|
+
if (this != &other) {
|
|
476
|
+
NodeApiPointerValueHolder temp(std::move(*this));
|
|
477
|
+
ptr_ = std::exchange(other.ptr_, nullptr);
|
|
478
|
+
}
|
|
479
|
+
return *this;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
~NodeApiPointerValueHolder() {
|
|
483
|
+
if (NodeApiRefCountedPointerValue *ptr = std::exchange(ptr_, nullptr)) {
|
|
484
|
+
deleter(ptr);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
NodeApiRefCountedPointerValue *operator->() const {
|
|
489
|
+
return ptr_;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
NodeApiRefCountedPointerValue *get() const {
|
|
493
|
+
return ptr_;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
NodeApiRefCountedPointerValue *release() {
|
|
497
|
+
return std::exchange(ptr_, nullptr);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
explicit operator bool() const {
|
|
501
|
+
return ptr_ != nullptr;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
NodeApiPointerValueHolder(NodeApiPointerValueHolder const &) = delete;
|
|
505
|
+
NodeApiPointerValueHolder &operator=(NodeApiPointerValueHolder const &) = delete;
|
|
506
|
+
|
|
507
|
+
private:
|
|
508
|
+
NodeApiRefCountedPointerValue *ptr_{};
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
using NodeApiStackValueHolder = NodeApiPointerValueHolder<&NodeApiRefCountedPointerValue::deleteStackValue>;
|
|
512
|
+
using NodeApiRefHolder = NodeApiPointerValueHolder<&NodeApiRefCountedPointerValue::deleteNodeApiRef>;
|
|
513
|
+
|
|
514
|
+
// SmallBuffer keeps InplaceSize elements in place in the class, and uses heap memory for more elements.
|
|
515
|
+
template <typename T, size_t InplaceSize>
|
|
516
|
+
class SmallBuffer {
|
|
517
|
+
public:
|
|
518
|
+
SmallBuffer(size_t size) noexcept;
|
|
519
|
+
|
|
520
|
+
T *data() noexcept;
|
|
521
|
+
size_t size() const noexcept;
|
|
522
|
+
|
|
523
|
+
SmallBuffer(const SmallBuffer &) = delete;
|
|
524
|
+
SmallBuffer &operator=(const SmallBuffer &) = delete;
|
|
525
|
+
|
|
526
|
+
private:
|
|
527
|
+
size_t size_{};
|
|
528
|
+
std::array<T, InplaceSize> stackData_{};
|
|
529
|
+
std::unique_ptr<T[]> heapData_{};
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// The number of arguments that we keep on stack. We use heap if we have more arguments.
|
|
533
|
+
constexpr static size_t MaxStackArgCount = 8;
|
|
534
|
+
|
|
535
|
+
// NodeApiValueArgs helps optimize passing arguments to NAPI functions.
|
|
536
|
+
// If number of arguments is below or equal to MaxStackArgCount, they are kept on the call stack,
|
|
537
|
+
// otherwise arguments are allocated on the heap.
|
|
538
|
+
class NodeApiValueArgs {
|
|
539
|
+
public:
|
|
540
|
+
NodeApiValueArgs(NodeApiJsiRuntime &runtime, span<const jsi::Value> args);
|
|
541
|
+
operator span<napi_value>();
|
|
542
|
+
|
|
543
|
+
NodeApiValueArgs(const NodeApiValueArgs &) = delete;
|
|
544
|
+
NodeApiValueArgs &operator=(const NodeApiValueArgs &) = delete;
|
|
545
|
+
|
|
546
|
+
private:
|
|
547
|
+
SmallBuffer<napi_value, MaxStackArgCount> args_;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// Helps to use the stack storage for a temporary conversion from napi_value to jsi::Value.
|
|
551
|
+
// It also helps to avoid a conversion to a relatively expensive napi_ref.
|
|
552
|
+
class JsiValueView {
|
|
553
|
+
public:
|
|
554
|
+
union StoreType {
|
|
555
|
+
NodeApiStackOnlyPointerValue value_;
|
|
556
|
+
std::array<std::byte, sizeof(NodeApiStackOnlyPointerValue)> bytes_;
|
|
557
|
+
StoreType() {}
|
|
558
|
+
~StoreType() {}
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
public:
|
|
562
|
+
JsiValueView(NodeApiJsiRuntime *runtime, napi_value jsValue);
|
|
563
|
+
operator const jsi::Value &() const noexcept;
|
|
564
|
+
|
|
565
|
+
static jsi::Value initValue(NodeApiJsiRuntime *runtime, napi_value jsValue, StoreType *store);
|
|
566
|
+
|
|
567
|
+
JsiValueView(const JsiValueView &) = delete;
|
|
568
|
+
JsiValueView &operator=(const JsiValueView &) = delete;
|
|
569
|
+
|
|
570
|
+
private:
|
|
571
|
+
StoreType pointerStore_;
|
|
572
|
+
jsi::Value value_{};
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
// Helps to use stack storage for passing arguments that must be temporarily converted
|
|
576
|
+
// from napi_value to jsi::Value.
|
|
577
|
+
// It helps to avoid conversion to a relatively expensive napi_ref.
|
|
578
|
+
class JsiValueViewArgs {
|
|
579
|
+
public:
|
|
580
|
+
JsiValueViewArgs(NodeApiJsiRuntime *runtime, span<napi_value> args) noexcept;
|
|
581
|
+
const jsi::Value *data() noexcept;
|
|
582
|
+
size_t size() const noexcept;
|
|
583
|
+
|
|
584
|
+
JsiValueViewArgs(const JsiValueViewArgs &);
|
|
585
|
+
JsiValueViewArgs &operator=(const JsiValueViewArgs &);
|
|
586
|
+
|
|
587
|
+
private:
|
|
588
|
+
using StoreType = JsiValueView::StoreType;
|
|
589
|
+
SmallBuffer<StoreType, MaxStackArgCount> pointerStore_{0};
|
|
590
|
+
SmallBuffer<jsi::Value, MaxStackArgCount> args_{0};
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// Helps to use stack storage for a temporary conversion from napi_value to jsi::PropNameID.
|
|
594
|
+
// It helps to avoid conversions to a relatively expensive napi_ref.
|
|
595
|
+
class PropNameIDView {
|
|
596
|
+
public:
|
|
597
|
+
PropNameIDView(NodeApiJsiRuntime *runtime, napi_value propertyId) noexcept;
|
|
598
|
+
operator const jsi::PropNameID &() const noexcept;
|
|
599
|
+
|
|
600
|
+
PropNameIDView(const PropNameIDView &);
|
|
601
|
+
PropNameIDView &operator=(const PropNameIDView &);
|
|
602
|
+
|
|
603
|
+
private:
|
|
604
|
+
using StoreType = JsiValueView::StoreType;
|
|
605
|
+
StoreType pointerStore_{};
|
|
606
|
+
jsi::PropNameID const propertyId_;
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
// Wraps up the jsi::HostFunctionType along with the NodeApiJsiRuntime.
|
|
610
|
+
class HostFunctionWrapper {
|
|
611
|
+
public:
|
|
612
|
+
HostFunctionWrapper(jsi::HostFunctionType &&hostFunction, NodeApiJsiRuntime &runtime);
|
|
613
|
+
|
|
614
|
+
jsi::HostFunctionType &hostFunction() noexcept;
|
|
615
|
+
NodeApiJsiRuntime &runtime() noexcept;
|
|
616
|
+
|
|
617
|
+
HostFunctionWrapper(const HostFunctionWrapper &) = delete;
|
|
618
|
+
HostFunctionWrapper &operator=(const HostFunctionWrapper &) = delete;
|
|
619
|
+
|
|
620
|
+
private:
|
|
621
|
+
jsi::HostFunctionType hostFunction_;
|
|
622
|
+
NodeApiJsiRuntime &runtime_;
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
// Wraps up the jsr_prepared_script.
|
|
626
|
+
class NodeApiPreparedJavaScript final : public jsi::PreparedJavaScript {
|
|
627
|
+
public:
|
|
628
|
+
NodeApiPreparedJavaScript(napi_env env, jsr_prepared_script script, std::string sourceURL)
|
|
629
|
+
: env_(env), script_(script), sourceURL_(std::move(sourceURL)) {}
|
|
630
|
+
|
|
631
|
+
~NodeApiPreparedJavaScript() override {
|
|
632
|
+
JSRuntimeApi::current()->jsr_delete_prepared_script(env_, script_);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
jsr_prepared_script getScript() const {
|
|
636
|
+
return script_;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const std::string &sourceURL() const {
|
|
640
|
+
return sourceURL_;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
NodeApiPreparedJavaScript(const NodeApiPreparedJavaScript &) = delete;
|
|
644
|
+
NodeApiPreparedJavaScript &operator=(const NodeApiPreparedJavaScript &) = delete;
|
|
645
|
+
|
|
646
|
+
private:
|
|
647
|
+
napi_env env_;
|
|
648
|
+
jsr_prepared_script script_;
|
|
649
|
+
std::string sourceURL_;
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
private: // Error-handling utility methods
|
|
653
|
+
template <typename... Args>
|
|
654
|
+
jsi::JSError makeJSError(Args &&...args);
|
|
655
|
+
[[noreturn]] void throwJSException(napi_status errorCode) const;
|
|
656
|
+
[[noreturn]] void throwNativeException(char const *errorMessage) const;
|
|
657
|
+
void rewriteErrorMessage(napi_value jsError) const;
|
|
658
|
+
template <typename TLambda>
|
|
659
|
+
auto runInMethodContext(char const *methodName, TLambda lambda);
|
|
660
|
+
template <typename TLambda>
|
|
661
|
+
napi_value handleCallbackExceptions(TLambda lambda) const noexcept;
|
|
662
|
+
bool setException(napi_value error) const noexcept;
|
|
663
|
+
bool setException(std::string_view message) const noexcept;
|
|
664
|
+
|
|
665
|
+
private: // Shared NAPI call helpers
|
|
666
|
+
napi_valuetype typeOf(napi_value value) const;
|
|
667
|
+
bool strictEquals(napi_value left, napi_value right) const;
|
|
668
|
+
napi_value getUndefined() const;
|
|
669
|
+
napi_value getNull() const;
|
|
670
|
+
napi_value getGlobal() const;
|
|
671
|
+
napi_value getBoolean(bool value) const;
|
|
672
|
+
bool getValueBool(napi_value value) const;
|
|
673
|
+
napi_value createInt32(int32_t value) const;
|
|
674
|
+
napi_value createUInt32(uint32_t value) const;
|
|
675
|
+
napi_value createDouble(double value) const;
|
|
676
|
+
double getValueDouble(napi_value value) const;
|
|
677
|
+
napi_value createStringLatin1(std::string_view value) const;
|
|
678
|
+
napi_value createStringUtf8(std::string_view value) const;
|
|
679
|
+
napi_value createStringUtf8(const uint8_t *data, size_t length) const;
|
|
680
|
+
std::string stringToStdString(napi_value stringValue) const;
|
|
681
|
+
napi_value getPropertyIdFromName(std::string_view value) const;
|
|
682
|
+
napi_value getPropertyIdFromName(const uint8_t *data, size_t length) const;
|
|
683
|
+
napi_value getPropertyIdFromName(napi_value str) const;
|
|
684
|
+
napi_value getPropertyIdFromSymbol(napi_value sym) const;
|
|
685
|
+
std::string propertyIdToStdString(napi_value propertyId);
|
|
686
|
+
napi_value createSymbol(std::string_view symbolDescription) const;
|
|
687
|
+
std::string symbolToStdString(napi_value symbolValue);
|
|
688
|
+
napi_value callFunction(napi_value thisArg, napi_value function, span<napi_value> args = {}) const;
|
|
689
|
+
napi_value constructObject(napi_value constructor, span<napi_value> args = {}) const;
|
|
690
|
+
bool instanceOf(napi_value object, napi_value constructor) const;
|
|
691
|
+
napi_value createNodeApiObject() const;
|
|
692
|
+
bool hasProperty(napi_value object, napi_value propertyId) const;
|
|
693
|
+
napi_value getProperty(napi_value object, napi_value propertyId) const;
|
|
694
|
+
void setProperty(napi_value object, napi_value propertyId, napi_value value) const;
|
|
695
|
+
void setProperty(napi_value object, napi_value propertyId, napi_value value, napi_property_attributes attrs) const;
|
|
696
|
+
napi_value createNodeApiArray(size_t length) const;
|
|
697
|
+
bool isArray(napi_value value) const;
|
|
698
|
+
size_t getArrayLength(napi_value value) const;
|
|
699
|
+
napi_value getElement(napi_value arr, size_t index) const;
|
|
700
|
+
void setElement(napi_value array, uint32_t index, napi_value value) const;
|
|
701
|
+
static napi_value __cdecl jsiHostFunctionCallback(napi_env env, napi_callback_info info) noexcept;
|
|
702
|
+
napi_value createExternalFunction(napi_value name, int32_t paramCount, napi_callback callback, void *callbackData);
|
|
703
|
+
napi_value createExternalObject(void *data, napi_finalize finalizeCallback) const;
|
|
704
|
+
template <typename T>
|
|
705
|
+
napi_value createExternalObject(std::unique_ptr<T> &&data) const;
|
|
706
|
+
void *getExternalData(napi_value object) const;
|
|
707
|
+
const std::shared_ptr<jsi::HostObject> &getJsiHostObject(napi_value obj);
|
|
708
|
+
napi_value getHostObjectProxyHandler();
|
|
709
|
+
template <napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>), size_t argCount>
|
|
710
|
+
void setProxyTrap(napi_value handler, napi_value propertyName);
|
|
711
|
+
napi_value hostObjectHasTrap(span<napi_value> args);
|
|
712
|
+
napi_value hostObjectGetTrap(span<napi_value> args);
|
|
713
|
+
napi_value hostObjectSetTrap(span<napi_value> args);
|
|
714
|
+
napi_value hostObjectOwnKeysTrap(span<napi_value> args);
|
|
715
|
+
napi_value hostObjectGetOwnPropertyDescriptorTrap(span<napi_value> args);
|
|
716
|
+
|
|
717
|
+
private: // Miscellaneous utility methods
|
|
718
|
+
span<const uint8_t> toSpan(const jsi::Buffer &buffer);
|
|
719
|
+
jsi::Value toJsiValue(napi_value value) const;
|
|
720
|
+
napi_value getNodeApiValue(const jsi::Value &value) const;
|
|
721
|
+
napi_value getNodeApiValue(const jsi::Pointer &ptr) const;
|
|
722
|
+
napi_value getNodeApiValue(const NodeApiRefHolder &ref) const;
|
|
723
|
+
NodeApiRefCountedPointerValue *cloneNodeApiPointerValue(const PointerValue *pointerValue);
|
|
724
|
+
std::optional<uint32_t> toArrayIndex(std::string::const_iterator first, std::string::const_iterator last);
|
|
725
|
+
|
|
726
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::Object, T>, int> = 0>
|
|
727
|
+
T makeJsiPointer(napi_value value) const;
|
|
728
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::String, T>, int> = 0>
|
|
729
|
+
T makeJsiPointer(napi_value value) const;
|
|
730
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int> = 0>
|
|
731
|
+
T makeJsiPointer(napi_value value) const;
|
|
732
|
+
#if JSI_VERSION >= 6
|
|
733
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int> = 0>
|
|
734
|
+
T makeJsiPointer(napi_value value) const;
|
|
735
|
+
#endif
|
|
736
|
+
template <
|
|
737
|
+
typename TTo,
|
|
738
|
+
typename TFrom,
|
|
739
|
+
std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int> = 0,
|
|
740
|
+
std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int> = 0>
|
|
741
|
+
TTo cloneAs(const TFrom &pointer) const;
|
|
742
|
+
NodeApiRefHolder makeNodeApiRef(napi_value value, NodeApiPointerValueKind pointerKind, int32_t initialRefCount = 2);
|
|
743
|
+
|
|
744
|
+
void addStackValue(NodeApiStackValueHolder &&pointerHolder);
|
|
745
|
+
void addRef(NodeApiRefHolder &&refHolder);
|
|
746
|
+
void pushPointerValueScope() noexcept;
|
|
747
|
+
void popPointerValueScope() noexcept;
|
|
748
|
+
void collectUnusedStackValues();
|
|
749
|
+
void collectUnusedRefs() noexcept;
|
|
750
|
+
|
|
751
|
+
napi_env getEnv() const noexcept {
|
|
752
|
+
return env_;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
private: // Fields
|
|
756
|
+
napi_env env_{};
|
|
757
|
+
JSRuntimeApi *jsrApi_;
|
|
758
|
+
std::function<void()> onDelete_;
|
|
759
|
+
std::string sourceURL_;
|
|
760
|
+
|
|
761
|
+
// Property ID cache to improve execution speed.
|
|
762
|
+
struct PropertyId {
|
|
763
|
+
NodeApiRefHolder Error;
|
|
764
|
+
NodeApiRefHolder Object;
|
|
765
|
+
NodeApiRefHolder Proxy;
|
|
766
|
+
NodeApiRefHolder Symbol;
|
|
767
|
+
NodeApiRefHolder byteLength;
|
|
768
|
+
NodeApiRefHolder configurable;
|
|
769
|
+
NodeApiRefHolder enumerable;
|
|
770
|
+
NodeApiRefHolder get;
|
|
771
|
+
NodeApiRefHolder getOwnPropertyDescriptor;
|
|
772
|
+
NodeApiRefHolder has;
|
|
773
|
+
NodeApiRefHolder hostFunctionSymbol;
|
|
774
|
+
NodeApiRefHolder hostObjectSymbol;
|
|
775
|
+
NodeApiRefHolder length;
|
|
776
|
+
NodeApiRefHolder message;
|
|
777
|
+
NodeApiRefHolder ownKeys;
|
|
778
|
+
NodeApiRefHolder propertyIsEnumerable;
|
|
779
|
+
NodeApiRefHolder prototype;
|
|
780
|
+
NodeApiRefHolder set;
|
|
781
|
+
NodeApiRefHolder stack;
|
|
782
|
+
NodeApiRefHolder toString;
|
|
783
|
+
NodeApiRefHolder value;
|
|
784
|
+
NodeApiRefHolder writable;
|
|
785
|
+
} propertyId_;
|
|
786
|
+
|
|
787
|
+
// Cache of commonly used values.
|
|
788
|
+
struct CachedValue {
|
|
789
|
+
NodeApiRefHolder Error;
|
|
790
|
+
NodeApiRefHolder Global;
|
|
791
|
+
NodeApiRefHolder HostObjectProxyHandler;
|
|
792
|
+
NodeApiRefHolder ProxyConstructor;
|
|
793
|
+
NodeApiRefHolder SymbolToString;
|
|
794
|
+
} cachedValue_;
|
|
795
|
+
|
|
796
|
+
bool hasPendingJSError_{false};
|
|
797
|
+
|
|
798
|
+
std::vector<size_t> stackScopes_;
|
|
799
|
+
std::vector<NodeApiStackValueHolder> stackValues_;
|
|
800
|
+
std::vector<NodeApiRefHolder> refs_;
|
|
801
|
+
|
|
802
|
+
// TODO: implement GC for propNameIDs_
|
|
803
|
+
std::unordered_map<StringKey, NodeApiRefHolder, StringKey::Hash, StringKey::EqualTo> propNameIDs_;
|
|
804
|
+
|
|
805
|
+
NodeApiJsiRuntime &runtime{*this};
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
//=====================================================================================================================
|
|
809
|
+
// StringKey implementation
|
|
810
|
+
//=====================================================================================================================
|
|
811
|
+
|
|
812
|
+
StringKey::StringKey(std::string &&string) noexcept
|
|
813
|
+
: string_(std::move(string)), type_(Type::String), hash_(std::hash<std::string_view>{}(string_)) {}
|
|
814
|
+
|
|
815
|
+
StringKey::StringKey(std::string_view view) noexcept
|
|
816
|
+
: view_(view), type_(Type::View), hash_(std::hash<std::string_view>{}(view_)) {}
|
|
817
|
+
|
|
818
|
+
StringKey::StringKey(const char *data, size_t length) noexcept
|
|
819
|
+
: view_(data, length), type_(Type::View), hash_(std::hash<std::string_view>{}(view_)) {}
|
|
820
|
+
|
|
821
|
+
StringKey::StringKey(StringKey &&other) noexcept : type_(other.type_), hash_(std::exchange(other.hash_, 0)) {
|
|
822
|
+
if (type_ == Type::String) {
|
|
823
|
+
::new (std::addressof(string_)) std::string(std::move(other.string_));
|
|
824
|
+
} else {
|
|
825
|
+
::new (std::addressof(view_)) std::string_view(std::exchange(other.view_, std::string_view()));
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
StringKey &StringKey::operator=(StringKey &&other) noexcept {
|
|
830
|
+
if (this != &other) {
|
|
831
|
+
this->~StringKey();
|
|
832
|
+
::new (this) StringKey(std::move(other));
|
|
833
|
+
}
|
|
834
|
+
return *this;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
StringKey::~StringKey() {
|
|
838
|
+
if (type_ == Type::String) {
|
|
839
|
+
std::addressof(string_)->~basic_string();
|
|
840
|
+
} else {
|
|
841
|
+
std::addressof(view_)->~basic_string_view();
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
std::string_view StringKey::getStringView() const {
|
|
846
|
+
return (type_ == Type::String) ? std::string_view(string_) : view_;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
bool StringKey::equalTo(const StringKey &other) const {
|
|
850
|
+
return getStringView().compare(other.getStringView()) == 0;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
size_t StringKey::hash() const {
|
|
854
|
+
return hash_;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
size_t StringKey::Hash::operator()(const StringKey &key) const {
|
|
858
|
+
return key.hash();
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
bool StringKey::EqualTo::operator()(const StringKey &left, const StringKey &right) const {
|
|
862
|
+
return left.equalTo(right);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
//=====================================================================================================================
|
|
866
|
+
// NodeApiJsiRuntime implementation
|
|
867
|
+
//=====================================================================================================================
|
|
868
|
+
|
|
869
|
+
NodeApiJsiRuntime::NodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept
|
|
870
|
+
: env_(env), jsrApi_(jsrApi), onDelete_(std::move(onDelete)) {
|
|
871
|
+
NodeApiScope scope{*this};
|
|
872
|
+
propertyId_.Error = makeNodeApiRef(getPropertyIdFromName("Error"), NodeApiPointerValueKind::String);
|
|
873
|
+
propertyId_.Object = makeNodeApiRef(getPropertyIdFromName("Object"), NodeApiPointerValueKind::String);
|
|
874
|
+
propertyId_.Proxy = makeNodeApiRef(getPropertyIdFromName("Proxy"), NodeApiPointerValueKind::String);
|
|
875
|
+
propertyId_.Symbol = makeNodeApiRef(getPropertyIdFromName("Symbol"), NodeApiPointerValueKind::String);
|
|
876
|
+
propertyId_.byteLength = makeNodeApiRef(getPropertyIdFromName("byteLength"), NodeApiPointerValueKind::String);
|
|
877
|
+
propertyId_.configurable = makeNodeApiRef(getPropertyIdFromName("configurable"), NodeApiPointerValueKind::String);
|
|
878
|
+
propertyId_.enumerable = makeNodeApiRef(getPropertyIdFromName("enumerable"), NodeApiPointerValueKind::String);
|
|
879
|
+
propertyId_.get = makeNodeApiRef(getPropertyIdFromName("get"), NodeApiPointerValueKind::String);
|
|
880
|
+
propertyId_.getOwnPropertyDescriptor =
|
|
881
|
+
makeNodeApiRef(getPropertyIdFromName("getOwnPropertyDescriptor"), NodeApiPointerValueKind::String);
|
|
882
|
+
propertyId_.has = makeNodeApiRef(getPropertyIdFromName("has"), NodeApiPointerValueKind::String);
|
|
883
|
+
propertyId_.hostFunctionSymbol = makeNodeApiRef(createSymbol("hostFunctionSymbol"), NodeApiPointerValueKind::Symbol);
|
|
884
|
+
propertyId_.hostObjectSymbol = makeNodeApiRef(createSymbol("hostObjectSymbol"), NodeApiPointerValueKind::Symbol);
|
|
885
|
+
propertyId_.length = makeNodeApiRef(getPropertyIdFromName("length"), NodeApiPointerValueKind::String);
|
|
886
|
+
propertyId_.message = makeNodeApiRef(getPropertyIdFromName("message"), NodeApiPointerValueKind::String);
|
|
887
|
+
propertyId_.ownKeys = makeNodeApiRef(getPropertyIdFromName("ownKeys"), NodeApiPointerValueKind::String);
|
|
888
|
+
propertyId_.propertyIsEnumerable =
|
|
889
|
+
makeNodeApiRef(getPropertyIdFromName("propertyIsEnumerable"), NodeApiPointerValueKind::String);
|
|
890
|
+
propertyId_.prototype = makeNodeApiRef(getPropertyIdFromName("prototype"), NodeApiPointerValueKind::String);
|
|
891
|
+
propertyId_.set = makeNodeApiRef(getPropertyIdFromName("set"), NodeApiPointerValueKind::String);
|
|
892
|
+
propertyId_.stack = makeNodeApiRef(getPropertyIdFromName("stack"), NodeApiPointerValueKind::String);
|
|
893
|
+
propertyId_.toString = makeNodeApiRef(getPropertyIdFromName("toString"), NodeApiPointerValueKind::String);
|
|
894
|
+
propertyId_.value = makeNodeApiRef(getPropertyIdFromName("value"), NodeApiPointerValueKind::String);
|
|
895
|
+
propertyId_.writable = makeNodeApiRef(getPropertyIdFromName("writable"), NodeApiPointerValueKind::String);
|
|
896
|
+
|
|
897
|
+
cachedValue_.Global = makeNodeApiRef(getGlobal(), NodeApiPointerValueKind::Object);
|
|
898
|
+
cachedValue_.Error = makeNodeApiRef(
|
|
899
|
+
getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Error)),
|
|
900
|
+
NodeApiPointerValueKind::Object);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
NodeApiJsiRuntime::~NodeApiJsiRuntime() {
|
|
904
|
+
if (onDelete_) {
|
|
905
|
+
onDelete_();
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
jsi::Value NodeApiJsiRuntime::evaluateJavaScript(
|
|
910
|
+
const std::shared_ptr<const jsi::Buffer> &buffer,
|
|
911
|
+
const std::string &sourceURL) {
|
|
912
|
+
return evaluatePreparedJavaScript(prepareJavaScript(buffer, sourceURL));
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
std::shared_ptr<const jsi::PreparedJavaScript> NodeApiJsiRuntime::prepareJavaScript(
|
|
916
|
+
const std::shared_ptr<const jsi::Buffer> &sourceBuffer,
|
|
917
|
+
std::string sourceURL) {
|
|
918
|
+
NodeApiScope scope{*this};
|
|
919
|
+
jsr_prepared_script script{};
|
|
920
|
+
napi_status status = jsrApi_->jsr_create_prepared_script(
|
|
921
|
+
env_,
|
|
922
|
+
sourceBuffer->data(),
|
|
923
|
+
sourceBuffer->size(),
|
|
924
|
+
[](void * /*data*/, void *deleterData) {
|
|
925
|
+
delete reinterpret_cast<std::shared_ptr<const jsi::Buffer> *>(deleterData);
|
|
926
|
+
},
|
|
927
|
+
new std::shared_ptr<const jsi::Buffer>(sourceBuffer),
|
|
928
|
+
sourceURL.c_str(),
|
|
929
|
+
&script);
|
|
930
|
+
CHECK_NAPI(status); // Not for the call to keep better automated formatting.
|
|
931
|
+
return std::make_shared<NodeApiPreparedJavaScript>(env_, script, std::move(sourceURL));
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
jsi::Value NodeApiJsiRuntime::evaluatePreparedJavaScript(const std::shared_ptr<const jsi::PreparedJavaScript> &js) {
|
|
935
|
+
NodeApiScope scope{*this};
|
|
936
|
+
auto preparedScript = static_cast<const NodeApiPreparedJavaScript *>(js.get());
|
|
937
|
+
AutoRestore<std::string> sourceURLScope{sourceURL_, preparedScript->sourceURL()};
|
|
938
|
+
napi_value result{};
|
|
939
|
+
CHECK_NAPI(jsrApi_->jsr_prepared_script_run(env_, preparedScript->getScript(), &result));
|
|
940
|
+
return toJsiValue(result);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
#if JSI_VERSION >= 4
|
|
944
|
+
bool NodeApiJsiRuntime::drainMicrotasks(int maxMicrotasksHint) {
|
|
945
|
+
bool result{};
|
|
946
|
+
CHECK_NAPI(jsrApi_->jsr_drain_microtasks(env_, maxMicrotasksHint, &result));
|
|
947
|
+
return result;
|
|
948
|
+
}
|
|
949
|
+
#endif
|
|
950
|
+
|
|
951
|
+
jsi::Object NodeApiJsiRuntime::global() {
|
|
952
|
+
return make<jsi::Object>(cachedValue_.Global->clone(*this));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
std::string NodeApiJsiRuntime::description() {
|
|
956
|
+
const char *desc{};
|
|
957
|
+
CHECK_NAPI(jsrApi_->jsr_get_description(env_, &desc));
|
|
958
|
+
return desc;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
bool NodeApiJsiRuntime::isInspectable() {
|
|
962
|
+
bool result{};
|
|
963
|
+
CHECK_NAPI(jsrApi_->jsr_is_inspectable(env_, &result));
|
|
964
|
+
return result;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneSymbol(const jsi::Runtime::PointerValue *pointerValue) {
|
|
968
|
+
return cloneNodeApiPointerValue(pointerValue);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
#if JSI_VERSION >= 6
|
|
972
|
+
jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneBigInt(const jsi::Runtime::PointerValue *pointerValue) {
|
|
973
|
+
return cloneNodeApiPointerValue(pointerValue);
|
|
974
|
+
}
|
|
975
|
+
#endif
|
|
976
|
+
|
|
977
|
+
jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneString(const jsi::Runtime::PointerValue *pointerValue) {
|
|
978
|
+
return cloneNodeApiPointerValue(pointerValue);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneObject(const jsi::Runtime::PointerValue *pointerValue) {
|
|
982
|
+
return cloneNodeApiPointerValue(pointerValue);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
jsi::Runtime::PointerValue *NodeApiJsiRuntime::clonePropNameID(const jsi::Runtime::PointerValue *pointerValue) {
|
|
986
|
+
return cloneNodeApiPointerValue(pointerValue);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromAscii(const char *str, size_t length) {
|
|
990
|
+
NodeApiScope scope{*this};
|
|
991
|
+
StringKey keyName{str, length};
|
|
992
|
+
auto it = propNameIDs_.find(keyName);
|
|
993
|
+
if (it != propNameIDs_.end()) {
|
|
994
|
+
return make<jsi::PropNameID>(it->second->clone(*this));
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
napi_value obj = createNodeApiObject();
|
|
998
|
+
napi_value propName{};
|
|
999
|
+
CHECK_NAPI(jsrApi_->napi_create_string_latin1(env_, str, length, &propName));
|
|
1000
|
+
CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
|
|
1001
|
+
napi_value props{};
|
|
1002
|
+
CHECK_NAPI(jsrApi_->napi_get_all_property_names(
|
|
1003
|
+
env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
|
|
1004
|
+
napi_value propNameId = getElement(props, 0);
|
|
1005
|
+
NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
|
|
1006
|
+
jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
|
|
1007
|
+
propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) {
|
|
1012
|
+
NodeApiScope scope{*this};
|
|
1013
|
+
StringKey keyName{reinterpret_cast<const char *>(utf8), length};
|
|
1014
|
+
auto it = propNameIDs_.find(keyName);
|
|
1015
|
+
if (it != propNameIDs_.end()) {
|
|
1016
|
+
return make<jsi::PropNameID>(it->second->clone(*this));
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
napi_value obj = createNodeApiObject();
|
|
1020
|
+
napi_value propName{};
|
|
1021
|
+
CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, reinterpret_cast<const char *>(utf8), length, &propName));
|
|
1022
|
+
CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
|
|
1023
|
+
napi_value props{};
|
|
1024
|
+
CHECK_NAPI(jsrApi_->napi_get_all_property_names(
|
|
1025
|
+
env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
|
|
1026
|
+
napi_value propNameId = getElement(props, 0);
|
|
1027
|
+
NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
|
|
1028
|
+
jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
|
|
1029
|
+
propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
|
|
1030
|
+
return result;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromString(const jsi::String &str) {
|
|
1034
|
+
NodeApiScope scope{*this};
|
|
1035
|
+
const NodeApiPointerValue *pv = static_cast<const NodeApiPointerValue *>(getPointerValue(str));
|
|
1036
|
+
if (pv->getKind() == NodeApiPointerValueKind::StringPropNameID) {
|
|
1037
|
+
return make<jsi::PropNameID>(pv->clone(*this));
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
StringKey keyName(utf8(str));
|
|
1041
|
+
auto it = propNameIDs_.find(keyName);
|
|
1042
|
+
if (it != propNameIDs_.end()) {
|
|
1043
|
+
return make<jsi::PropNameID>(it->second->clone(*this));
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
napi_value napiStr = const_cast<NodeApiPointerValue *>(pv)->getValue(*this);
|
|
1047
|
+
|
|
1048
|
+
napi_value obj = createNodeApiObject();
|
|
1049
|
+
setProperty(obj, napiStr, getUndefined());
|
|
1050
|
+
napi_value props{};
|
|
1051
|
+
CHECK_NAPI(jsrApi_->napi_get_all_property_names(
|
|
1052
|
+
env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
|
|
1053
|
+
napi_value propNameId = getElement(props, 0);
|
|
1054
|
+
NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
|
|
1055
|
+
jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
|
|
1056
|
+
propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
|
|
1057
|
+
return result;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
#if JSI_VERSION >= 5
|
|
1061
|
+
jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromSymbol(const jsi::Symbol &sym) {
|
|
1062
|
+
// TODO: Should we ensure uniqueness of symbols?
|
|
1063
|
+
return cloneAs<jsi::PropNameID>(sym);
|
|
1064
|
+
}
|
|
1065
|
+
#endif
|
|
1066
|
+
|
|
1067
|
+
std::string NodeApiJsiRuntime::utf8(const jsi::PropNameID &id) {
|
|
1068
|
+
NodeApiScope scope{*this};
|
|
1069
|
+
return propertyIdToStdString(getNodeApiValue(id));
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
bool NodeApiJsiRuntime::compare(const jsi::PropNameID &lhs, const jsi::PropNameID &rhs) {
|
|
1073
|
+
NodeApiScope scope{*this};
|
|
1074
|
+
return getPointerValue(lhs) == getPointerValue(rhs) || strictEquals(getNodeApiValue(lhs), getNodeApiValue(rhs));
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
std::string NodeApiJsiRuntime::symbolToString(const jsi::Symbol &sym) {
|
|
1078
|
+
NodeApiScope scope{*this};
|
|
1079
|
+
return symbolToStdString(getNodeApiValue(sym));
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
#if JSI_VERSION >= 8
|
|
1083
|
+
jsi::BigInt NodeApiJsiRuntime::createBigIntFromInt64(int64_t val) {
|
|
1084
|
+
NodeApiScope scope{*this};
|
|
1085
|
+
napi_value bigint{};
|
|
1086
|
+
CHECK_NAPI(jsrApi_->napi_create_bigint_int64(env_, val, &bigint));
|
|
1087
|
+
return makeJsiPointer<jsi::BigInt>(bigint);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
jsi::BigInt NodeApiJsiRuntime::createBigIntFromUint64(uint64_t val) {
|
|
1091
|
+
NodeApiScope scope{*this};
|
|
1092
|
+
napi_value bigint{};
|
|
1093
|
+
CHECK_NAPI(jsrApi_->napi_create_bigint_uint64(env_, val, &bigint));
|
|
1094
|
+
return makeJsiPointer<jsi::BigInt>(bigint);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
bool NodeApiJsiRuntime::bigintIsInt64(const jsi::BigInt &bigint) {
|
|
1098
|
+
NodeApiScope scope{*this};
|
|
1099
|
+
napi_value value = getNodeApiValue(bigint);
|
|
1100
|
+
bool lossless{false};
|
|
1101
|
+
int64_t result{};
|
|
1102
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bigint_int64(env_, value, &result, &lossless));
|
|
1103
|
+
return lossless;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
bool NodeApiJsiRuntime::bigintIsUint64(const jsi::BigInt &bigint) {
|
|
1107
|
+
NodeApiScope scope{*this};
|
|
1108
|
+
napi_value value = getNodeApiValue(bigint);
|
|
1109
|
+
bool lossless{false};
|
|
1110
|
+
uint64_t result{};
|
|
1111
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
|
|
1112
|
+
return lossless;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
uint64_t NodeApiJsiRuntime::truncate(const jsi::BigInt &bigint) {
|
|
1116
|
+
NodeApiScope scope{*this};
|
|
1117
|
+
napi_value value = getNodeApiValue(bigint);
|
|
1118
|
+
bool lossless{false};
|
|
1119
|
+
uint64_t result{};
|
|
1120
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
|
|
1121
|
+
return result;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
inline uint32_t constexpr maxCharsPerDigitInRadix(int32_t radix) {
|
|
1125
|
+
// To compute the lower bound of bits in a BigIntDigitType "covered" by a
|
|
1126
|
+
// char. For power of 2 radixes, it is known (exactly) that each character
|
|
1127
|
+
// covers log2(radix) bits. For non-power of 2 radixes, a lower bound is
|
|
1128
|
+
// log2(greatest power of 2 that is less than radix).
|
|
1129
|
+
uint32_t minNumBitsPerChar = radix < 4 ? 1 : radix < 8 ? 2 : radix < 16 ? 3 : radix < 32 ? 4 : 5;
|
|
1130
|
+
|
|
1131
|
+
// With minNumBitsPerChar being the lower bound estimate of how many bits each
|
|
1132
|
+
// char can represent, the upper bound of how many chars "fit" in a bigint
|
|
1133
|
+
// digit is ceil(sizeofInBits(bigint digit) / minNumBitsPerChar).
|
|
1134
|
+
uint32_t numCharsPerDigits = static_cast<uint32_t>(sizeof(uint64_t)) / (1 << minNumBitsPerChar);
|
|
1135
|
+
|
|
1136
|
+
return numCharsPerDigits;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Return the high 32 bits of a 64 bit value.
|
|
1140
|
+
constexpr inline uint32_t Hi_32(uint64_t Value) {
|
|
1141
|
+
return static_cast<uint32_t>(Value >> 32);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Return the low 32 bits of a 64 bit value.
|
|
1145
|
+
constexpr inline uint32_t Lo_32(uint64_t Value) {
|
|
1146
|
+
return static_cast<uint32_t>(Value);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// Make a 64-bit integer from a high / low pair of 32-bit integers.
|
|
1150
|
+
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
|
1151
|
+
return ((uint64_t)High << 32) | (uint64_t)Low;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
jsi::String NodeApiJsiRuntime::bigintToString(const jsi::BigInt &bigint, int32_t radix) {
|
|
1155
|
+
NodeApiScope scope{*this};
|
|
1156
|
+
if (radix < 2 || radix > 36) {
|
|
1157
|
+
throw makeJSError("Invalid radix ", radix, " to BigInt.toString");
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
napi_value value = getNodeApiValue(bigint);
|
|
1161
|
+
size_t wordCount{};
|
|
1162
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(env_, value, nullptr, &wordCount, nullptr));
|
|
1163
|
+
uint64_t stackWords[8]{};
|
|
1164
|
+
std::unique_ptr<uint64_t[]> heapWords;
|
|
1165
|
+
uint64_t *words = stackWords;
|
|
1166
|
+
if (wordCount > std::size(stackWords)) {
|
|
1167
|
+
heapWords = std::unique_ptr<uint64_t[]>(new uint64_t[wordCount]);
|
|
1168
|
+
words = heapWords.get();
|
|
1169
|
+
}
|
|
1170
|
+
int32_t signBit{};
|
|
1171
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(env_, value, &signBit, &wordCount, words));
|
|
1172
|
+
|
|
1173
|
+
if (wordCount == 0) {
|
|
1174
|
+
return createStringFromAscii("0", 1);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// avoid trashing the heap by pre-allocating the largest possible string
|
|
1178
|
+
// returned by this function. The "1" below is to account for a possible "-"
|
|
1179
|
+
// sign.
|
|
1180
|
+
std::string digits;
|
|
1181
|
+
digits.reserve(1 + wordCount * maxCharsPerDigitInRadix(radix));
|
|
1182
|
+
|
|
1183
|
+
// Use 32-bit values for calculations to get 64-bit results.
|
|
1184
|
+
// For the little-endian machines we just cast the words array.
|
|
1185
|
+
// TODO: Add support for big-endian.
|
|
1186
|
+
uint32_t *halfWords = reinterpret_cast<uint32_t *>(words);
|
|
1187
|
+
size_t count = wordCount * 2;
|
|
1188
|
+
for (size_t i = count; i > 0 && halfWords[i - 1] == 0; --i) {
|
|
1189
|
+
--count;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
uint32_t divisor = static_cast<uint32_t>(radix);
|
|
1193
|
+
uint32_t remainder = 0;
|
|
1194
|
+
uint64_t word0 = words[0];
|
|
1195
|
+
|
|
1196
|
+
do {
|
|
1197
|
+
// We rewrite the halfWords array as we divide it by radix.
|
|
1198
|
+
if (count <= 2) {
|
|
1199
|
+
remainder = word0 % divisor;
|
|
1200
|
+
word0 = word0 / divisor;
|
|
1201
|
+
} else {
|
|
1202
|
+
for (size_t i = count; i > 0; --i) {
|
|
1203
|
+
uint64_t partialDividend = Make_64(remainder, halfWords[i - 1]);
|
|
1204
|
+
if (partialDividend == 0) {
|
|
1205
|
+
halfWords[i] = 0;
|
|
1206
|
+
remainder = 0;
|
|
1207
|
+
if (i == count) {
|
|
1208
|
+
if (--count == 2) {
|
|
1209
|
+
word0 = words[0];
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
} else if (partialDividend < divisor) {
|
|
1213
|
+
halfWords[i] = 0;
|
|
1214
|
+
remainder = Lo_32(partialDividend);
|
|
1215
|
+
if (i == count) {
|
|
1216
|
+
if (--count == 2) {
|
|
1217
|
+
word0 = words[0];
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
} else if (partialDividend == divisor) {
|
|
1221
|
+
halfWords[i] = 1;
|
|
1222
|
+
remainder = 0;
|
|
1223
|
+
} else {
|
|
1224
|
+
halfWords[i] = Lo_32(partialDividend / divisor);
|
|
1225
|
+
remainder = Lo_32(partialDividend % divisor);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
if (remainder < 10) {
|
|
1231
|
+
digits.push_back(static_cast<char>('0' + remainder));
|
|
1232
|
+
} else {
|
|
1233
|
+
digits.push_back(static_cast<char>('a' + remainder - 10));
|
|
1234
|
+
}
|
|
1235
|
+
} while (count > 2 || word0 != 0);
|
|
1236
|
+
|
|
1237
|
+
if (signBit) {
|
|
1238
|
+
digits.push_back('-');
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
std::reverse(digits.begin(), digits.end());
|
|
1242
|
+
return createStringFromAscii(digits.data(), digits.size());
|
|
1243
|
+
}
|
|
1244
|
+
#endif
|
|
1245
|
+
|
|
1246
|
+
jsi::String NodeApiJsiRuntime::createStringFromAscii(const char *str, size_t length) {
|
|
1247
|
+
NodeApiScope scope{*this};
|
|
1248
|
+
return makeJsiPointer<jsi::String>(createStringLatin1({str, length}));
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
jsi::String NodeApiJsiRuntime::createStringFromUtf8(const uint8_t *str, size_t length) {
|
|
1252
|
+
NodeApiScope scope{*this};
|
|
1253
|
+
return makeJsiPointer<jsi::String>(createStringUtf8(str, length));
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
std::string NodeApiJsiRuntime::utf8(const jsi::String &str) {
|
|
1257
|
+
NodeApiScope scope{*this};
|
|
1258
|
+
return stringToStdString(getNodeApiValue(str));
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
jsi::Object NodeApiJsiRuntime::createObject() {
|
|
1262
|
+
NodeApiScope scope{*this};
|
|
1263
|
+
return makeJsiPointer<jsi::Object>(createNodeApiObject());
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
jsi::Object NodeApiJsiRuntime::createObject(std::shared_ptr<jsi::HostObject> hostObject) {
|
|
1267
|
+
NodeApiScope scope{*this};
|
|
1268
|
+
// The hostObjectHolder keeps the hostObject as external data.
|
|
1269
|
+
// Then, the hostObjectHolder is wrapped up by a Proxy object to provide access
|
|
1270
|
+
// to the hostObject's get, set, and getPropertyNames methods.
|
|
1271
|
+
// There is a special symbol property ID, 'hostObjectSymbol', used to access the hostObjectWrapper from the Proxy.
|
|
1272
|
+
napi_value hostObjectHolder =
|
|
1273
|
+
createExternalObject(std::make_unique<std::shared_ptr<jsi::HostObject>>(std::move(hostObject)));
|
|
1274
|
+
napi_value obj = createNodeApiObject();
|
|
1275
|
+
setProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol), hostObjectHolder);
|
|
1276
|
+
if (!cachedValue_.ProxyConstructor) {
|
|
1277
|
+
cachedValue_.ProxyConstructor = makeNodeApiRef(
|
|
1278
|
+
getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Proxy)),
|
|
1279
|
+
NodeApiPointerValueKind::Object);
|
|
1280
|
+
}
|
|
1281
|
+
napi_value args[] = {obj, getHostObjectProxyHandler()};
|
|
1282
|
+
napi_value proxy = constructObject(getNodeApiValue(cachedValue_.ProxyConstructor), args);
|
|
1283
|
+
return makeJsiPointer<jsi::Object>(proxy);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
std::shared_ptr<jsi::HostObject> NodeApiJsiRuntime::getHostObject(const jsi::Object &obj) {
|
|
1287
|
+
NodeApiScope scope{*this};
|
|
1288
|
+
return getJsiHostObject(getNodeApiValue(obj));
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
jsi::HostFunctionType &NodeApiJsiRuntime::getHostFunction(const jsi::Function &func) {
|
|
1292
|
+
NodeApiScope scope{*this};
|
|
1293
|
+
napi_value hostFunctionHolder = getProperty(getNodeApiValue(func), getNodeApiValue((propertyId_.hostFunctionSymbol)));
|
|
1294
|
+
if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
|
|
1295
|
+
return static_cast<HostFunctionWrapper *>(getExternalData(hostFunctionHolder))->hostFunction();
|
|
1296
|
+
} else {
|
|
1297
|
+
throw jsi::JSINativeException("getHostFunction() can only be called with HostFunction.");
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
#if JSI_VERSION >= 7
|
|
1302
|
+
bool NodeApiJsiRuntime::hasNativeState(const jsi::Object &obj) {
|
|
1303
|
+
NodeApiScope scope{*this};
|
|
1304
|
+
void *nativeState{};
|
|
1305
|
+
napi_status status = jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState);
|
|
1306
|
+
return status == napi_ok && nativeState != nullptr;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
std::shared_ptr<jsi::NativeState> NodeApiJsiRuntime::getNativeState(const jsi::Object &obj) {
|
|
1310
|
+
NodeApiScope scope{*this};
|
|
1311
|
+
void *nativeState{};
|
|
1312
|
+
CHECK_NAPI(jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState));
|
|
1313
|
+
if (nativeState != nullptr) {
|
|
1314
|
+
return *reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState);
|
|
1315
|
+
} else {
|
|
1316
|
+
return std::shared_ptr<jsi::NativeState>();
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
void NodeApiJsiRuntime::setNativeState(const jsi::Object &obj, std::shared_ptr<jsi::NativeState> state) {
|
|
1321
|
+
NodeApiScope scope{*this};
|
|
1322
|
+
if (hasNativeState(obj)) {
|
|
1323
|
+
void *nativeState{};
|
|
1324
|
+
CHECK_NAPI(jsrApi_->napi_remove_wrap(env_, getNodeApiValue(obj), &nativeState));
|
|
1325
|
+
if (nativeState != nullptr) {
|
|
1326
|
+
std::shared_ptr<jsi::NativeState> oldState{
|
|
1327
|
+
std::move(*reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState))};
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
if (state) {
|
|
1332
|
+
CHECK_NAPI(jsrApi_->napi_wrap(
|
|
1333
|
+
env_,
|
|
1334
|
+
getNodeApiValue(obj),
|
|
1335
|
+
new std::shared_ptr<jsi::NativeState>(std::move(state)),
|
|
1336
|
+
[](napi_env /*env*/, void *data, void * /*finalize_hint*/) {
|
|
1337
|
+
std::shared_ptr<jsi::NativeState> oldState{
|
|
1338
|
+
std::move(*reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(data))};
|
|
1339
|
+
},
|
|
1340
|
+
nullptr,
|
|
1341
|
+
nullptr));
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
#endif
|
|
1345
|
+
|
|
1346
|
+
jsi::Value NodeApiJsiRuntime::getProperty(const jsi::Object &obj, const jsi::PropNameID &name) {
|
|
1347
|
+
NodeApiScope scope{*this};
|
|
1348
|
+
return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
jsi::Value NodeApiJsiRuntime::getProperty(const jsi::Object &obj, const jsi::String &name) {
|
|
1352
|
+
NodeApiScope scope{*this};
|
|
1353
|
+
return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
bool NodeApiJsiRuntime::hasProperty(const jsi::Object &obj, const jsi::PropNameID &name) {
|
|
1357
|
+
NodeApiScope scope{*this};
|
|
1358
|
+
return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
bool NodeApiJsiRuntime::hasProperty(const jsi::Object &obj, const jsi::String &name) {
|
|
1362
|
+
NodeApiScope scope{*this};
|
|
1363
|
+
return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
void NodeApiJsiRuntime::setPropertyValue(
|
|
1367
|
+
JSI_CONST_10 jsi::Object &obj,
|
|
1368
|
+
const jsi::PropNameID &name,
|
|
1369
|
+
const jsi::Value &value) {
|
|
1370
|
+
NodeApiScope scope{*this};
|
|
1371
|
+
setProperty(getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
void NodeApiJsiRuntime::setPropertyValue(
|
|
1375
|
+
JSI_CONST_10 jsi::Object &obj,
|
|
1376
|
+
const jsi::String &name,
|
|
1377
|
+
const jsi::Value &value) {
|
|
1378
|
+
NodeApiScope scope{*this};
|
|
1379
|
+
setProperty(getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
bool NodeApiJsiRuntime::isArray(const jsi::Object &obj) const {
|
|
1383
|
+
NodeApiScope scope{*this};
|
|
1384
|
+
return isArray(getNodeApiValue(obj));
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
bool NodeApiJsiRuntime::isArrayBuffer(const jsi::Object &obj) const {
|
|
1388
|
+
NodeApiScope scope{*this};
|
|
1389
|
+
bool result{};
|
|
1390
|
+
CHECK_NAPI(jsrApi_->napi_is_arraybuffer(env_, getNodeApiValue(obj), &result));
|
|
1391
|
+
return result;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
bool NodeApiJsiRuntime::isFunction(const jsi::Object &obj) const {
|
|
1395
|
+
NodeApiScope scope{*this};
|
|
1396
|
+
return typeOf(getNodeApiValue(obj)) == napi_valuetype::napi_function;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
bool NodeApiJsiRuntime::isHostObject(const jsi::Object &obj) const {
|
|
1400
|
+
NodeApiScope scope{*this};
|
|
1401
|
+
napi_value hostObjectHolder = getProperty(getNodeApiValue(obj), getNodeApiValue(propertyId_.hostObjectSymbol));
|
|
1402
|
+
if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
|
|
1403
|
+
return getExternalData(hostObjectHolder) != nullptr;
|
|
1404
|
+
} else {
|
|
1405
|
+
return false;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
bool NodeApiJsiRuntime::isHostFunction(const jsi::Function &func) const {
|
|
1410
|
+
NodeApiScope scope{*this};
|
|
1411
|
+
napi_value hostFunctionHolder = getProperty(getNodeApiValue(func), getNodeApiValue(propertyId_.hostFunctionSymbol));
|
|
1412
|
+
if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
|
|
1413
|
+
return getExternalData(hostFunctionHolder) != nullptr;
|
|
1414
|
+
} else {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
jsi::Array NodeApiJsiRuntime::getPropertyNames(const jsi::Object &obj) {
|
|
1420
|
+
NodeApiScope scope{*this};
|
|
1421
|
+
napi_value properties;
|
|
1422
|
+
CHECK_NAPI(jsrApi_->napi_get_all_property_names(
|
|
1423
|
+
env_,
|
|
1424
|
+
getNodeApiValue(obj),
|
|
1425
|
+
napi_key_collection_mode::napi_key_include_prototypes,
|
|
1426
|
+
napi_key_filter(napi_key_enumerable | napi_key_skip_symbols),
|
|
1427
|
+
napi_key_numbers_to_strings,
|
|
1428
|
+
&properties));
|
|
1429
|
+
return makeJsiPointer<jsi::Object>(properties).asArray(*this);
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
jsi::WeakObject NodeApiJsiRuntime::createWeakObject(const jsi::Object &obj) {
|
|
1433
|
+
NodeApiScope scope{*this};
|
|
1434
|
+
return make<jsi::WeakObject>(NodeApiRefCountedPointerValue::make(
|
|
1435
|
+
*const_cast<NodeApiJsiRuntime *>(this), getNodeApiValue(obj), NodeApiPointerValueKind::WeakObject));
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
jsi::Value NodeApiJsiRuntime::lockWeakObject(JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObject) {
|
|
1439
|
+
NodeApiScope scope{*this};
|
|
1440
|
+
napi_value value = getNodeApiValue(weakObject);
|
|
1441
|
+
if (value) {
|
|
1442
|
+
return toJsiValue(value);
|
|
1443
|
+
} else {
|
|
1444
|
+
return jsi::Value::undefined();
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
jsi::Array NodeApiJsiRuntime::createArray(size_t length) {
|
|
1449
|
+
NodeApiScope scope{*this};
|
|
1450
|
+
return makeJsiPointer<jsi::Object>(createNodeApiArray(length)).asArray(*this);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
#if JSI_VERSION >= 9
|
|
1454
|
+
jsi::ArrayBuffer NodeApiJsiRuntime::createArrayBuffer(std::shared_ptr<jsi::MutableBuffer> buffer) {
|
|
1455
|
+
NodeApiScope scope{*this};
|
|
1456
|
+
napi_value result{};
|
|
1457
|
+
void *data = buffer->data();
|
|
1458
|
+
size_t size = buffer->size();
|
|
1459
|
+
CHECK_NAPI(jsrApi_->napi_create_external_arraybuffer(
|
|
1460
|
+
env_,
|
|
1461
|
+
data,
|
|
1462
|
+
size,
|
|
1463
|
+
[](napi_env /*env*/, void * /*data*/, void *finalizeHint) {
|
|
1464
|
+
std::shared_ptr<jsi::MutableBuffer> buffer{
|
|
1465
|
+
std::move(*reinterpret_cast<std::shared_ptr<jsi::MutableBuffer> *>(finalizeHint))};
|
|
1466
|
+
},
|
|
1467
|
+
new std::shared_ptr<jsi::MutableBuffer>{std::move(buffer)},
|
|
1468
|
+
&result));
|
|
1469
|
+
return makeJsiPointer<jsi::Object>(result).getArrayBuffer(*this);
|
|
1470
|
+
}
|
|
1471
|
+
#endif
|
|
1472
|
+
|
|
1473
|
+
size_t NodeApiJsiRuntime::size(const jsi::Array &arr) {
|
|
1474
|
+
NodeApiScope scope{*this};
|
|
1475
|
+
return getArrayLength(getNodeApiValue(arr));
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
size_t NodeApiJsiRuntime::size(const jsi::ArrayBuffer &arrBuf) {
|
|
1479
|
+
NodeApiScope scope{*this};
|
|
1480
|
+
size_t result{};
|
|
1481
|
+
CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(env_, getNodeApiValue(arrBuf), nullptr, &result));
|
|
1482
|
+
return result;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
uint8_t *NodeApiJsiRuntime::data(const jsi::ArrayBuffer &arrBuf) {
|
|
1486
|
+
NodeApiScope scope{*this};
|
|
1487
|
+
uint8_t *result{};
|
|
1488
|
+
CHECK_NAPI(
|
|
1489
|
+
jsrApi_->napi_get_arraybuffer_info(env_, getNodeApiValue(arrBuf), reinterpret_cast<void **>(&result), nullptr));
|
|
1490
|
+
return result;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
jsi::Value NodeApiJsiRuntime::getValueAtIndex(const jsi::Array &arr, size_t index) {
|
|
1494
|
+
NodeApiScope scope{*this};
|
|
1495
|
+
return toJsiValue(getElement(getNodeApiValue(arr), index));
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
void NodeApiJsiRuntime::setValueAtIndexImpl(JSI_CONST_10 jsi::Array &arr, size_t index, const jsi::Value &value) {
|
|
1499
|
+
NodeApiScope scope{*this};
|
|
1500
|
+
setElement(getNodeApiValue(arr), static_cast<uint32_t>(index), getNodeApiValue(value));
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
jsi::Function NodeApiJsiRuntime::createFunctionFromHostFunction(
|
|
1504
|
+
const jsi::PropNameID &name,
|
|
1505
|
+
unsigned int paramCount,
|
|
1506
|
+
jsi::HostFunctionType func) {
|
|
1507
|
+
NodeApiScope scope{*this};
|
|
1508
|
+
auto hostFunctionWrapper = std::make_unique<HostFunctionWrapper>(std::move(func), *this);
|
|
1509
|
+
napi_value function = createExternalFunction(
|
|
1510
|
+
getNodeApiValue(name), static_cast<int32_t>(paramCount), jsiHostFunctionCallback, hostFunctionWrapper.get());
|
|
1511
|
+
|
|
1512
|
+
const napi_value hostFunctionHolder = createExternalObject(std::move(hostFunctionWrapper));
|
|
1513
|
+
setProperty(
|
|
1514
|
+
function,
|
|
1515
|
+
getNodeApiValue(propertyId_.hostFunctionSymbol),
|
|
1516
|
+
hostFunctionHolder,
|
|
1517
|
+
napi_property_attributes::napi_default);
|
|
1518
|
+
return makeJsiPointer<jsi::Object>(function).getFunction(*this);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
jsi::Value
|
|
1522
|
+
NodeApiJsiRuntime::call(const jsi::Function &func, const jsi::Value &jsThis, const jsi::Value *args, size_t count) {
|
|
1523
|
+
NodeApiScope scope{*this};
|
|
1524
|
+
return toJsiValue(callFunction(
|
|
1525
|
+
getNodeApiValue(jsThis), getNodeApiValue(func), NodeApiValueArgs(*this, span<const jsi::Value>(args, count))));
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
jsi::Value NodeApiJsiRuntime::callAsConstructor(const jsi::Function &func, const jsi::Value *args, size_t count) {
|
|
1529
|
+
NodeApiScope scope{*this};
|
|
1530
|
+
return toJsiValue(
|
|
1531
|
+
constructObject(getNodeApiValue(func), NodeApiValueArgs(*this, span<jsi::Value const>(args, count))));
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
jsi::Runtime::ScopeState *NodeApiJsiRuntime::pushScope() {
|
|
1535
|
+
NodeApiEnvScope scope{getEnv()};
|
|
1536
|
+
napi_handle_scope result{};
|
|
1537
|
+
CHECK_NAPI(jsrApi_->napi_open_handle_scope(env_, &result));
|
|
1538
|
+
pushPointerValueScope();
|
|
1539
|
+
return reinterpret_cast<jsi::Runtime::ScopeState *>(result);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
void NodeApiJsiRuntime::popScope(jsi::Runtime::ScopeState *state) {
|
|
1543
|
+
NodeApiEnvScope scope{getEnv()};
|
|
1544
|
+
popPointerValueScope();
|
|
1545
|
+
CHECK_NAPI(jsrApi_->napi_close_handle_scope(env_, reinterpret_cast<napi_handle_scope>(state)));
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
bool NodeApiJsiRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const {
|
|
1549
|
+
NodeApiScope scope{*this};
|
|
1550
|
+
return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
#if JSI_VERSION >= 6
|
|
1554
|
+
bool NodeApiJsiRuntime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const {
|
|
1555
|
+
NodeApiScope scope{*this};
|
|
1556
|
+
return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
|
|
1557
|
+
}
|
|
1558
|
+
#endif
|
|
1559
|
+
|
|
1560
|
+
bool NodeApiJsiRuntime::strictEquals(const jsi::String &a, const jsi::String &b) const {
|
|
1561
|
+
NodeApiScope scope{*this};
|
|
1562
|
+
return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
bool NodeApiJsiRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b) const {
|
|
1566
|
+
NodeApiScope scope{*this};
|
|
1567
|
+
return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
bool NodeApiJsiRuntime::instanceOf(const jsi::Object &obj, const jsi::Function &func) {
|
|
1571
|
+
NodeApiScope scope{*this};
|
|
1572
|
+
return instanceOf(getNodeApiValue(obj), getNodeApiValue(func));
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
#if JSI_VERSION >= 11
|
|
1576
|
+
void NodeApiJsiRuntime::setExternalMemoryPressure(const jsi::Object &/*obj*/, size_t /*amount*/) {
|
|
1577
|
+
// TODO: implement
|
|
1578
|
+
}
|
|
1579
|
+
#endif
|
|
1580
|
+
|
|
1581
|
+
//=====================================================================================================================
|
|
1582
|
+
// NodeApiJsiRuntime::NodeApiScope implementation
|
|
1583
|
+
//=====================================================================================================================
|
|
1584
|
+
|
|
1585
|
+
NodeApiJsiRuntime::NodeApiScope::NodeApiScope(const NodeApiJsiRuntime &runtime) noexcept
|
|
1586
|
+
: NodeApiScope(const_cast<NodeApiJsiRuntime &>(runtime)) {}
|
|
1587
|
+
|
|
1588
|
+
NodeApiJsiRuntime::NodeApiScope::NodeApiScope(NodeApiJsiRuntime &runtime) noexcept
|
|
1589
|
+
: runtime_(runtime), envScope_(runtime_.getEnv()), scopeState_(runtime_.pushScope()) {}
|
|
1590
|
+
|
|
1591
|
+
NodeApiJsiRuntime::NodeApiScope::~NodeApiScope() noexcept {
|
|
1592
|
+
runtime_.popScope(scopeState_);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
//=====================================================================================================================
|
|
1596
|
+
// NodeApiJsiRuntime::NodeApiPointerValueScope implementation
|
|
1597
|
+
//=====================================================================================================================
|
|
1598
|
+
|
|
1599
|
+
NodeApiJsiRuntime::NodeApiPointerValueScope::NodeApiPointerValueScope(NodeApiJsiRuntime &runtime) noexcept
|
|
1600
|
+
: runtime_(runtime) {
|
|
1601
|
+
runtime_.pushPointerValueScope();
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
NodeApiJsiRuntime::NodeApiPointerValueScope::~NodeApiPointerValueScope() noexcept {
|
|
1605
|
+
runtime_.popPointerValueScope();
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
//=====================================================================================================================
|
|
1609
|
+
// NodeApiJsiRuntime::AutoRestore implementation
|
|
1610
|
+
//=====================================================================================================================
|
|
1611
|
+
|
|
1612
|
+
template <typename T>
|
|
1613
|
+
NodeApiJsiRuntime::AutoRestore<T>::AutoRestore(T &varRef, T newValue)
|
|
1614
|
+
: varRef_{varRef}, oldValue_{std::exchange(varRef, newValue)} {}
|
|
1615
|
+
|
|
1616
|
+
template <typename T>
|
|
1617
|
+
NodeApiJsiRuntime::AutoRestore<T>::~AutoRestore() {
|
|
1618
|
+
varRef_ = oldValue_;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
//=====================================================================================================================
|
|
1622
|
+
// NodeApiJsiRuntime::NodeApiStackOnlyPointerValue implementation
|
|
1623
|
+
//=====================================================================================================================
|
|
1624
|
+
|
|
1625
|
+
NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::NodeApiStackOnlyPointerValue(
|
|
1626
|
+
napi_value value,
|
|
1627
|
+
NodeApiPointerValueKind pointerKind) noexcept
|
|
1628
|
+
: value_(value), pointerKind_(pointerKind) {}
|
|
1629
|
+
|
|
1630
|
+
// Intentionally do nothing.
|
|
1631
|
+
void NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::invalidate() noexcept {}
|
|
1632
|
+
|
|
1633
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::clone(
|
|
1634
|
+
NodeApiJsiRuntime &runtime) const {
|
|
1635
|
+
return NodeApiRefCountedPointerValue::make(runtime, value_, pointerKind_);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
napi_value NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getValue(NodeApiJsiRuntime & /*runtime*/) noexcept {
|
|
1639
|
+
return value_;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
NodeApiJsiRuntime::NodeApiPointerValueKind NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getKind() const noexcept {
|
|
1643
|
+
return pointerKind_;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
//=====================================================================================================================
|
|
1647
|
+
// NodeApiJsiRuntime::NodeApiPointerValue implementation
|
|
1648
|
+
//=====================================================================================================================
|
|
1649
|
+
|
|
1650
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue::NodeApiRefCountedPointerValue(
|
|
1651
|
+
napi_value value,
|
|
1652
|
+
NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
|
|
1653
|
+
int32_t initialRefCount) noexcept
|
|
1654
|
+
: value_(value), pointerKind_(pointerKind), refCount_(initialRefCount) {}
|
|
1655
|
+
|
|
1656
|
+
/*static*/ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::make(
|
|
1657
|
+
NodeApiJsiRuntime &runtime,
|
|
1658
|
+
napi_value value,
|
|
1659
|
+
NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
|
|
1660
|
+
int32_t initialRefCount) {
|
|
1661
|
+
NodeApiRefCountedPointerValue *result = new NodeApiRefCountedPointerValue(value, pointerKind, initialRefCount);
|
|
1662
|
+
runtime.addStackValue(NodeApiStackValueHolder(result));
|
|
1663
|
+
return result;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
/*static*/ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
|
|
1667
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue::makeNodeApiRef(
|
|
1668
|
+
NodeApiJsiRuntime &runtime,
|
|
1669
|
+
napi_value value,
|
|
1670
|
+
NodeApiPointerValueKind pointerKind,
|
|
1671
|
+
int32_t initialRefCount) {
|
|
1672
|
+
return make(runtime, value, pointerKind, initialRefCount)->createNodeApiRef(runtime);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::invalidate() noexcept {
|
|
1676
|
+
decRefCount();
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::clone(
|
|
1680
|
+
NodeApiJsiRuntime & /*runtime*/) const {
|
|
1681
|
+
incRefCount();
|
|
1682
|
+
return const_cast<NodeApiRefCountedPointerValue *>(this);
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
napi_value NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getValue(NodeApiJsiRuntime &runtime) noexcept {
|
|
1686
|
+
if (value_ != nullptr) {
|
|
1687
|
+
return value_;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
if (ref_ == nullptr) {
|
|
1691
|
+
return nullptr;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
JSRuntimeApi *jsrApi = JSRuntimeApi::current();
|
|
1695
|
+
if (pointerKind_ == NodeApiPointerValueKind::Object || pointerKind_ == NodeApiPointerValueKind::WeakObject) {
|
|
1696
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &value_));
|
|
1697
|
+
} else {
|
|
1698
|
+
napi_value obj{};
|
|
1699
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &obj));
|
|
1700
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_named_property(runtime.getEnv(), obj, kPrimitivePropertyName, &value_));
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
if (value_ != nullptr) {
|
|
1704
|
+
runtime.addStackValue(NodeApiStackValueHolder(this));
|
|
1705
|
+
incRefCount();
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
return value_;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
NodeApiJsiRuntime::NodeApiPointerValueKind NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getKind() const noexcept {
|
|
1712
|
+
return pointerKind_;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
/*static*/ bool NodeApiJsiRuntime::NodeApiRefCountedPointerValue::usedByJsiPointer(
|
|
1716
|
+
NodeApiRefCountedPointerValue *ptr) noexcept {
|
|
1717
|
+
if (ptr == nullptr)
|
|
1718
|
+
return false;
|
|
1719
|
+
const int32_t internalRefCount = (ptr->value_ != nullptr ? 1 : 0) + (ptr->ref_ != nullptr ? 1 : 0);
|
|
1720
|
+
const int32_t refCount = ptr->refCount_.load(std::memory_order_acquire);
|
|
1721
|
+
return refCount > internalRefCount;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
/*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteStackValue(
|
|
1725
|
+
NodeApiRefCountedPointerValue *ptr) noexcept {
|
|
1726
|
+
if (ptr != nullptr && ptr->value_ != nullptr) {
|
|
1727
|
+
ptr->value_ = nullptr;
|
|
1728
|
+
ptr->decRefCount();
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::convertToNodeApiRef(NodeApiJsiRuntime &runtime) noexcept {
|
|
1733
|
+
if (value_ == nullptr) {
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
if (ref_ == nullptr && usedByJsiPointer(this)) {
|
|
1738
|
+
createNodeApiRef(runtime);
|
|
1739
|
+
runtime.addRef(NodeApiRefHolder(this));
|
|
1740
|
+
value_ = nullptr;
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
value_ = nullptr;
|
|
1745
|
+
decRefCount();
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteNodeApiRef(
|
|
1750
|
+
NodeApiRefCountedPointerValue *ptr) noexcept {
|
|
1751
|
+
if (ptr != nullptr && ptr->ref_ != nullptr) {
|
|
1752
|
+
ptr->ref_ = nullptr;
|
|
1753
|
+
ptr->decRefCount();
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
/*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteNodeApiRef(
|
|
1758
|
+
NodeApiRefCountedPointerValue *ptr,
|
|
1759
|
+
NodeApiJsiRuntime &runtime) noexcept {
|
|
1760
|
+
if (ptr != nullptr && ptr->ref_ != nullptr) {
|
|
1761
|
+
CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_delete_reference(runtime.getEnv(), ptr->ref_));
|
|
1762
|
+
ptr->ref_ = nullptr;
|
|
1763
|
+
ptr->decRefCount();
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::incRefCount() const noexcept {
|
|
1768
|
+
refCount_.fetch_add(1, std::memory_order_relaxed);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::decRefCount() const noexcept {
|
|
1772
|
+
int32_t count = refCount_.fetch_sub(1, std::memory_order_release) - 1;
|
|
1773
|
+
if (count == 0) {
|
|
1774
|
+
std::atomic_thread_fence(std::memory_order_acquire);
|
|
1775
|
+
delete this;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::createNodeApiRef(
|
|
1780
|
+
NodeApiJsiRuntime &runtime) {
|
|
1781
|
+
JSRuntimeApi *jsrApi = JSRuntimeApi::current();
|
|
1782
|
+
CHECK_ELSE_CRASH(value_ != nullptr, "value_ must not be null");
|
|
1783
|
+
CHECK_ELSE_CRASH(ref_ == nullptr, "ref_ must be null");
|
|
1784
|
+
if (pointerKind_ == NodeApiPointerValueKind::Object) {
|
|
1785
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), value_, 1, &ref_));
|
|
1786
|
+
} else if (pointerKind_ != NodeApiPointerValueKind::WeakObject) {
|
|
1787
|
+
napi_value obj{};
|
|
1788
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_object(runtime.getEnv(), &obj));
|
|
1789
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_set_named_property(runtime.getEnv(), obj, kPrimitivePropertyName, value_));
|
|
1790
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), obj, 1, &ref_));
|
|
1791
|
+
} else {
|
|
1792
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), value_, 0, &ref_));
|
|
1793
|
+
}
|
|
1794
|
+
return this;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
//=====================================================================================================================
|
|
1798
|
+
// NodeApiJsiRuntime::SmallBuffer implementation
|
|
1799
|
+
//=====================================================================================================================
|
|
1800
|
+
|
|
1801
|
+
template <typename T, size_t InplaceSize>
|
|
1802
|
+
NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::SmallBuffer(size_t size) noexcept
|
|
1803
|
+
: size_{size}, heapData_{size_ > InplaceSize ? std::make_unique<T[]>(size_) : nullptr} {}
|
|
1804
|
+
|
|
1805
|
+
template <typename T, size_t InplaceSize>
|
|
1806
|
+
T *NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::data() noexcept {
|
|
1807
|
+
return heapData_ ? heapData_.get() : stackData_.data();
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
template <typename T, size_t InplaceSize>
|
|
1811
|
+
size_t NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::size() const noexcept {
|
|
1812
|
+
return size_;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
//=====================================================================================================================
|
|
1816
|
+
// NodeApiJsiRuntime::NodeApiValueArgs implementation
|
|
1817
|
+
//=====================================================================================================================
|
|
1818
|
+
|
|
1819
|
+
NodeApiJsiRuntime::NodeApiValueArgs::NodeApiValueArgs(NodeApiJsiRuntime &runtime, span<const jsi::Value> args)
|
|
1820
|
+
: args_{args.size()} {
|
|
1821
|
+
napi_value *jsArgs = args_.data();
|
|
1822
|
+
for (size_t i = 0; i < args.size(); ++i) {
|
|
1823
|
+
jsArgs[i] = runtime.getNodeApiValue(args[i]);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
NodeApiJsiRuntime::NodeApiValueArgs::operator span<napi_value>() {
|
|
1828
|
+
return span<napi_value>{args_.data(), args_.size()};
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
//=====================================================================================================================
|
|
1832
|
+
// NodeApiJsiRuntime::JsiValueView implementation
|
|
1833
|
+
//=====================================================================================================================
|
|
1834
|
+
|
|
1835
|
+
NodeApiJsiRuntime::JsiValueView::JsiValueView(NodeApiJsiRuntime *runtime, napi_value jsValue)
|
|
1836
|
+
: value_{initValue(runtime, jsValue, std::addressof(pointerStore_))} {}
|
|
1837
|
+
|
|
1838
|
+
NodeApiJsiRuntime::JsiValueView::operator const jsi::Value &() const noexcept {
|
|
1839
|
+
return value_;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
/*static*/ jsi::Value
|
|
1843
|
+
NodeApiJsiRuntime::JsiValueView::initValue(NodeApiJsiRuntime *runtime, napi_value value, StoreType *store) {
|
|
1844
|
+
switch (runtime->typeOf(value)) {
|
|
1845
|
+
case napi_valuetype::napi_undefined:
|
|
1846
|
+
return jsi::Value::undefined();
|
|
1847
|
+
case napi_valuetype::napi_null:
|
|
1848
|
+
return jsi::Value::null();
|
|
1849
|
+
case napi_valuetype::napi_boolean:
|
|
1850
|
+
return jsi::Value{runtime->getValueBool(value)};
|
|
1851
|
+
case napi_valuetype::napi_number:
|
|
1852
|
+
return jsi::Value{runtime->getValueDouble(value)};
|
|
1853
|
+
case napi_valuetype::napi_string:
|
|
1854
|
+
return make<jsi::String>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::String));
|
|
1855
|
+
case napi_valuetype::napi_symbol:
|
|
1856
|
+
return make<jsi::Symbol>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::Symbol));
|
|
1857
|
+
case napi_valuetype::napi_object:
|
|
1858
|
+
case napi_valuetype::napi_function:
|
|
1859
|
+
case napi_valuetype::napi_external:
|
|
1860
|
+
return make<jsi::Object>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::Object));
|
|
1861
|
+
#if JSI_VERSION >= 8
|
|
1862
|
+
case napi_valuetype::napi_bigint:
|
|
1863
|
+
return make<jsi::BigInt>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::BigInt));
|
|
1864
|
+
#endif
|
|
1865
|
+
default:
|
|
1866
|
+
throw jsi::JSINativeException("Unexpected value type");
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
//=====================================================================================================================
|
|
1871
|
+
// NodeApiJsiRuntime::JsiValueViewArgs implementation
|
|
1872
|
+
//=====================================================================================================================
|
|
1873
|
+
|
|
1874
|
+
NodeApiJsiRuntime::JsiValueViewArgs::JsiValueViewArgs(NodeApiJsiRuntime *runtime, span<napi_value> args) noexcept
|
|
1875
|
+
: pointerStore_{args.size()}, args_{args.size()} {
|
|
1876
|
+
JsiValueView::StoreType *pointerStore = pointerStore_.data();
|
|
1877
|
+
jsi::Value *jsiArgs = args_.data();
|
|
1878
|
+
for (size_t i = 0; i < args_.size(); ++i) {
|
|
1879
|
+
jsiArgs[i] = JsiValueView::initValue(runtime, args[i], std::addressof(pointerStore[i]));
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
jsi::Value const *NodeApiJsiRuntime::JsiValueViewArgs::data() noexcept {
|
|
1884
|
+
return args_.data();
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
size_t NodeApiJsiRuntime::JsiValueViewArgs::size() const noexcept {
|
|
1888
|
+
return args_.size();
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
//=====================================================================================================================
|
|
1892
|
+
// NodeApiJsiRuntime::PropNameIDView implementation
|
|
1893
|
+
//=====================================================================================================================
|
|
1894
|
+
|
|
1895
|
+
// TODO: account for symbol
|
|
1896
|
+
NodeApiJsiRuntime::PropNameIDView::PropNameIDView(NodeApiJsiRuntime * /*runtime*/, napi_value propertyId) noexcept
|
|
1897
|
+
: propertyId_{make<jsi::PropNameID>(new(std::addressof(
|
|
1898
|
+
pointerStore_)) NodeApiStackOnlyPointerValue(propertyId, NodeApiPointerValueKind::StringPropNameID))} {}
|
|
1899
|
+
|
|
1900
|
+
NodeApiJsiRuntime::PropNameIDView::operator jsi::PropNameID const &() const noexcept {
|
|
1901
|
+
return propertyId_;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
//=====================================================================================================================
|
|
1905
|
+
// NodeApiJsiRuntime::HostFunctionWrapper implementation
|
|
1906
|
+
//=====================================================================================================================
|
|
1907
|
+
|
|
1908
|
+
NodeApiJsiRuntime::HostFunctionWrapper::HostFunctionWrapper(jsi::HostFunctionType &&type, NodeApiJsiRuntime &runtime)
|
|
1909
|
+
: hostFunction_{std::move(type)}, runtime_{runtime} {}
|
|
1910
|
+
|
|
1911
|
+
jsi::HostFunctionType &NodeApiJsiRuntime::HostFunctionWrapper::hostFunction() noexcept {
|
|
1912
|
+
return hostFunction_;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
NodeApiJsiRuntime &NodeApiJsiRuntime::HostFunctionWrapper::runtime() noexcept {
|
|
1916
|
+
return runtime_;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
//=====================================================================================================================
|
|
1920
|
+
// NodeApiJsiRuntime implementation
|
|
1921
|
+
//=====================================================================================================================
|
|
1922
|
+
|
|
1923
|
+
template <typename... Args>
|
|
1924
|
+
jsi::JSError NodeApiJsiRuntime::makeJSError(Args &&...args) {
|
|
1925
|
+
std::ostringstream errorStream;
|
|
1926
|
+
((errorStream << std::forward<Args>(args)), ...);
|
|
1927
|
+
return jsi::JSError(*this, errorStream.str());
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
// Throws jsi::JSError or jsi::JSINativeException from Node-API error.
|
|
1931
|
+
[[noreturn]] void NodeApiJsiRuntime::throwJSException(napi_status status) const {
|
|
1932
|
+
napi_value jsError{};
|
|
1933
|
+
CHECK_NAPI_ELSE_CRASH(jsrApi_->napi_get_and_clear_last_exception(env_, &jsError));
|
|
1934
|
+
|
|
1935
|
+
if (!hasPendingJSError_ &&
|
|
1936
|
+
(status == napi_pending_exception || instanceOf(jsError, getNodeApiValue(cachedValue_.Error)))) {
|
|
1937
|
+
AutoRestore<bool> setValue(const_cast<NodeApiJsiRuntime *>(this)->hasPendingJSError_, true);
|
|
1938
|
+
rewriteErrorMessage(jsError);
|
|
1939
|
+
throw jsi::JSError(*const_cast<NodeApiJsiRuntime *>(this), toJsiValue(jsError));
|
|
1940
|
+
} else {
|
|
1941
|
+
std::ostringstream errorStream;
|
|
1942
|
+
errorStream << "A call to Node-API returned error code 0x" << std::hex << status << '.';
|
|
1943
|
+
throw jsi::JSINativeException(errorStream.str().c_str());
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// Throws jsi::JSINativeException with a message.
|
|
1948
|
+
[[noreturn]] void NodeApiJsiRuntime::throwNativeException(char const *errorMessage) const {
|
|
1949
|
+
throw jsi::JSINativeException(errorMessage);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// Rewrites error messages to match the JSI unit test expectations.
|
|
1953
|
+
void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
|
|
1954
|
+
// The code below must work correctly even if the 'message' getter throws.
|
|
1955
|
+
// In case when it throws, we ignore that exception.
|
|
1956
|
+
napi_value message{};
|
|
1957
|
+
napi_status status = jsrApi_->napi_get_property(env_, jsError, getNodeApiValue(propertyId_.message), &message);
|
|
1958
|
+
if (status != napi_ok) {
|
|
1959
|
+
// If the 'message' property getter throws, then we clear the exception and ignore it.
|
|
1960
|
+
napi_value ignoreJSError{};
|
|
1961
|
+
jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
|
|
1962
|
+
} else if (typeOf(message) == napi_string) {
|
|
1963
|
+
// JSI unit tests expect V8- or JSC-like messages for the stack overflow.
|
|
1964
|
+
if (stringToStdString(message) == "Out of stack space") {
|
|
1965
|
+
setProperty(
|
|
1966
|
+
jsError,
|
|
1967
|
+
getNodeApiValue(propertyId_.message),
|
|
1968
|
+
createStringUtf8("RangeError : Maximum call stack size exceeded"sv));
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
// Make sure that the call stack has the current URL
|
|
1973
|
+
if (!sourceURL_.empty()) {
|
|
1974
|
+
napi_value stack{};
|
|
1975
|
+
status = jsrApi_->napi_get_property(env_, jsError, getNodeApiValue(propertyId_.stack), &stack);
|
|
1976
|
+
if (status != napi_ok) {
|
|
1977
|
+
// If the 'stack' property getter throws, then we clear the exception and ignore it.
|
|
1978
|
+
napi_value ignoreJSError{};
|
|
1979
|
+
jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
|
|
1980
|
+
} else if (typeOf(message) == napi_string) {
|
|
1981
|
+
// JSI unit tests expect URL to be part of the call stack.
|
|
1982
|
+
std::string stackStr = stringToStdString(stack);
|
|
1983
|
+
if (stackStr.find(sourceURL_) == std::string::npos) {
|
|
1984
|
+
stackStr += sourceURL_ + '\n' + stackStr;
|
|
1985
|
+
setProperty(jsError, getNodeApiValue(propertyId_.stack), createStringUtf8(stackStr.c_str()));
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// Evaluates lambda and augments exception messages with the method's name.
|
|
1992
|
+
template <typename TLambda>
|
|
1993
|
+
auto NodeApiJsiRuntime::runInMethodContext(char const *methodName, TLambda lambda) {
|
|
1994
|
+
try {
|
|
1995
|
+
return lambda();
|
|
1996
|
+
} catch (jsi::JSError const &) {
|
|
1997
|
+
throw; // do not augment the JSError exceptions.
|
|
1998
|
+
} catch (std::exception const &ex) {
|
|
1999
|
+
throwNativeException((std::string{"Exception in "} + methodName + ": " + ex.what()).c_str());
|
|
2000
|
+
} catch (...) {
|
|
2001
|
+
throwNativeException((std::string{"Exception in "} + methodName + ": <unknown>").c_str());
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
// Evaluates lambda and converts all exceptions to NAPI errors.
|
|
2006
|
+
template <typename TLambda>
|
|
2007
|
+
napi_value NodeApiJsiRuntime::handleCallbackExceptions(TLambda lambda) const noexcept {
|
|
2008
|
+
try {
|
|
2009
|
+
try {
|
|
2010
|
+
return lambda();
|
|
2011
|
+
} catch (jsi::JSError const &jsError) {
|
|
2012
|
+
// This block may throw exceptions
|
|
2013
|
+
setException(getNodeApiValue(jsError.value()));
|
|
2014
|
+
}
|
|
2015
|
+
} catch (std::exception const &ex) {
|
|
2016
|
+
setException(ex.what());
|
|
2017
|
+
} catch (...) {
|
|
2018
|
+
setException("Unexpected error");
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
return getUndefined();
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
// Throws JavaScript exception using NAPI.
|
|
2025
|
+
bool NodeApiJsiRuntime::setException(napi_value error) const noexcept {
|
|
2026
|
+
// This method must not throw. We return false in case of error.
|
|
2027
|
+
return jsrApi_->napi_throw(env_, error) == napi_status::napi_ok;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// Throws JavaScript error exception with the provided message using NAPI.
|
|
2031
|
+
bool NodeApiJsiRuntime::setException(std::string_view message) const noexcept {
|
|
2032
|
+
// This method must not throw. We return false in case of error.
|
|
2033
|
+
return jsrApi_->napi_throw_error(env_, "Unknown", message.data()) == napi_status::napi_ok;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// Gets type of the napi_value.
|
|
2037
|
+
napi_valuetype NodeApiJsiRuntime::typeOf(napi_value value) const {
|
|
2038
|
+
napi_valuetype result{};
|
|
2039
|
+
CHECK_NAPI(jsrApi_->napi_typeof(env_, value, &result));
|
|
2040
|
+
return result;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// Returns true if two napi_values are strict equal per JavaScript rules.
|
|
2044
|
+
bool NodeApiJsiRuntime::strictEquals(napi_value left, napi_value right) const {
|
|
2045
|
+
bool result{false};
|
|
2046
|
+
CHECK_NAPI(jsrApi_->napi_strict_equals(env_, left, right, &result));
|
|
2047
|
+
return result;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
// Gets the napi_value for the JavaScript's undefined value.
|
|
2051
|
+
napi_value NodeApiJsiRuntime::getUndefined() const {
|
|
2052
|
+
napi_value result{nullptr};
|
|
2053
|
+
CHECK_NAPI(jsrApi_->napi_get_undefined(env_, &result));
|
|
2054
|
+
return result;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
// Gets the napi_value for the JavaScript's null value.
|
|
2058
|
+
napi_value NodeApiJsiRuntime::getNull() const {
|
|
2059
|
+
napi_value result{};
|
|
2060
|
+
CHECK_NAPI(jsrApi_->napi_get_null(env_, &result));
|
|
2061
|
+
return result;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
// Gets the napi_value for the JavaScript's global object.
|
|
2065
|
+
napi_value NodeApiJsiRuntime::getGlobal() const {
|
|
2066
|
+
napi_value result{nullptr};
|
|
2067
|
+
CHECK_NAPI(jsrApi_->napi_get_global(env_, &result));
|
|
2068
|
+
return result;
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// Gets the napi_value for the JavaScript's true and false values.
|
|
2072
|
+
napi_value NodeApiJsiRuntime::getBoolean(bool value) const {
|
|
2073
|
+
napi_value result{nullptr};
|
|
2074
|
+
CHECK_NAPI(jsrApi_->napi_get_boolean(env_, value, &result));
|
|
2075
|
+
return result;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
// Gets value of the Boolean napi_value.
|
|
2079
|
+
bool NodeApiJsiRuntime::getValueBool(napi_value value) const {
|
|
2080
|
+
bool result{nullptr};
|
|
2081
|
+
CHECK_NAPI(jsrApi_->napi_get_value_bool(env_, value, &result));
|
|
2082
|
+
return result;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
// Creates napi_value with an int32_t value.
|
|
2086
|
+
napi_value NodeApiJsiRuntime::createInt32(int32_t value) const {
|
|
2087
|
+
napi_value result{};
|
|
2088
|
+
CHECK_NAPI(jsrApi_->napi_create_int32(env_, value, &result));
|
|
2089
|
+
return result;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// Creates napi_value with an int32_t value.
|
|
2093
|
+
napi_value NodeApiJsiRuntime::createUInt32(uint32_t value) const {
|
|
2094
|
+
napi_value result{};
|
|
2095
|
+
CHECK_NAPI(jsrApi_->napi_create_uint32(env_, value, &result));
|
|
2096
|
+
return result;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
// Creates napi_value with a double value.
|
|
2100
|
+
napi_value NodeApiJsiRuntime::createDouble(double value) const {
|
|
2101
|
+
napi_value result{};
|
|
2102
|
+
CHECK_NAPI(jsrApi_->napi_create_double(env_, value, &result));
|
|
2103
|
+
return result;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// Gets value of the Double napi_value.
|
|
2107
|
+
double NodeApiJsiRuntime::getValueDouble(napi_value value) const {
|
|
2108
|
+
double result{0};
|
|
2109
|
+
CHECK_NAPI(jsrApi_->napi_get_value_double(env_, value, &result));
|
|
2110
|
+
return result;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// Creates a napi_value string from the extended ASCII symbols that correspond to the Latin1 encoding.
|
|
2114
|
+
// Each character is a byte-sized value from 0 to 255.
|
|
2115
|
+
napi_value NodeApiJsiRuntime::createStringLatin1(std::string_view value) const {
|
|
2116
|
+
CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
|
|
2117
|
+
napi_value result{};
|
|
2118
|
+
CHECK_NAPI(jsrApi_->napi_create_string_latin1(env_, value.data(), value.size(), &result));
|
|
2119
|
+
return result;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// Creates a napi_value string from a UTF-8 string.
|
|
2123
|
+
napi_value NodeApiJsiRuntime::createStringUtf8(std::string_view value) const {
|
|
2124
|
+
CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
|
|
2125
|
+
napi_value result{};
|
|
2126
|
+
CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, value.data(), value.size(), &result));
|
|
2127
|
+
return result;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
// Creates a napi_value string from a UTF-8 string. Use data and length instead of string_view.
|
|
2131
|
+
napi_value NodeApiJsiRuntime::createStringUtf8(const uint8_t *data, size_t length) const {
|
|
2132
|
+
return createStringUtf8({reinterpret_cast<const char *>(data), length});
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
// Gets std::string from the napi_value string.
|
|
2136
|
+
std::string NodeApiJsiRuntime::stringToStdString(napi_value stringValue) const {
|
|
2137
|
+
std::string result;
|
|
2138
|
+
CHECK_ELSE_THROW(
|
|
2139
|
+
typeOf(stringValue) == napi_valuetype::napi_string,
|
|
2140
|
+
"Cannot convert a non JS string Node-API Value to a std::string.");
|
|
2141
|
+
size_t strLength{};
|
|
2142
|
+
CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(env_, stringValue, nullptr, 0, &strLength));
|
|
2143
|
+
result.assign(strLength, '\0');
|
|
2144
|
+
size_t copiedLength{};
|
|
2145
|
+
CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(env_, stringValue, &result[0], result.length() + 1, &copiedLength));
|
|
2146
|
+
CHECK_ELSE_THROW(result.length() == copiedLength, "Unexpected string length");
|
|
2147
|
+
return result;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
// Gets or creates a unique string value from an UTF-8 string_view.
|
|
2151
|
+
napi_value NodeApiJsiRuntime::getPropertyIdFromName(std::string_view value) const {
|
|
2152
|
+
napi_value result{};
|
|
2153
|
+
CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, value.data(), value.size(), &result));
|
|
2154
|
+
return result;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// Gets or creates a unique string value from an UTF-8 data/length range.
|
|
2158
|
+
napi_value NodeApiJsiRuntime::getPropertyIdFromName(const uint8_t *data, size_t length) const {
|
|
2159
|
+
return getPropertyIdFromName({reinterpret_cast<const char *>(data), length});
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
// Gets or creates a unique string value from napi_value string.
|
|
2163
|
+
napi_value NodeApiJsiRuntime::getPropertyIdFromName(napi_value str) const {
|
|
2164
|
+
return str;
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
// Gets or creates a unique string value from napi_value symbol.
|
|
2168
|
+
napi_value NodeApiJsiRuntime::getPropertyIdFromSymbol(napi_value sym) const {
|
|
2169
|
+
return sym;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// Converts property id value to std::string.
|
|
2173
|
+
std::string NodeApiJsiRuntime::propertyIdToStdString(napi_value propertyId) {
|
|
2174
|
+
if (typeOf(propertyId) == napi_symbol) {
|
|
2175
|
+
return symbolToStdString(propertyId);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
return stringToStdString(propertyId);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
// Creates a JavaScript symbol napi_value.
|
|
2182
|
+
napi_value NodeApiJsiRuntime::createSymbol(std::string_view symbolDescription) const {
|
|
2183
|
+
napi_value result{};
|
|
2184
|
+
napi_value description = createStringUtf8(symbolDescription);
|
|
2185
|
+
CHECK_NAPI(jsrApi_->napi_create_symbol(env_, description, &result));
|
|
2186
|
+
return result;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// Calls Symbol.toString() and returns it as std::string.
|
|
2190
|
+
std::string NodeApiJsiRuntime::symbolToStdString(napi_value symbolValue) {
|
|
2191
|
+
if (!cachedValue_.SymbolToString) {
|
|
2192
|
+
napi_value symbolCtor = getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Symbol));
|
|
2193
|
+
napi_value symbolPrototype = getProperty(symbolCtor, getNodeApiValue(propertyId_.prototype));
|
|
2194
|
+
cachedValue_.SymbolToString = makeNodeApiRef(
|
|
2195
|
+
getProperty(symbolPrototype, getNodeApiValue(propertyId_.toString)), NodeApiPointerValueKind::Object);
|
|
2196
|
+
}
|
|
2197
|
+
napi_value jsString = callFunction(symbolValue, getNodeApiValue(cachedValue_.SymbolToString), {});
|
|
2198
|
+
return stringToStdString(jsString);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// Calls a JavaScript function.
|
|
2202
|
+
napi_value NodeApiJsiRuntime::callFunction(napi_value thisArg, napi_value function, span<napi_value> args) const {
|
|
2203
|
+
napi_value result{};
|
|
2204
|
+
CHECK_NAPI(jsrApi_->napi_call_function(env_, thisArg, function, args.size(), args.data(), &result));
|
|
2205
|
+
return result;
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// Constructs a new JavaScript Object using a constructor function.
|
|
2209
|
+
napi_value NodeApiJsiRuntime::constructObject(napi_value constructor, span<napi_value> args) const {
|
|
2210
|
+
napi_value result{};
|
|
2211
|
+
CHECK_NAPI(jsrApi_->napi_new_instance(env_, constructor, args.size(), args.data(), &result));
|
|
2212
|
+
return result;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
// Returns true if object was constructed using the provided constructor.
|
|
2216
|
+
bool NodeApiJsiRuntime::instanceOf(napi_value object, napi_value constructor) const {
|
|
2217
|
+
bool result{false};
|
|
2218
|
+
CHECK_NAPI(jsrApi_->napi_instanceof(env_, object, constructor, &result));
|
|
2219
|
+
return result;
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
// Creates new JavaScript Object.
|
|
2223
|
+
napi_value NodeApiJsiRuntime::createNodeApiObject() const {
|
|
2224
|
+
napi_value result{};
|
|
2225
|
+
CHECK_NAPI(jsrApi_->napi_create_object(env_, &result));
|
|
2226
|
+
return result;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
// Returns true if the object has a property with the provided property ID.
|
|
2230
|
+
bool NodeApiJsiRuntime::hasProperty(napi_value object, napi_value propertyId) const {
|
|
2231
|
+
bool result{};
|
|
2232
|
+
CHECK_NAPI(jsrApi_->napi_has_property(env_, object, propertyId, &result));
|
|
2233
|
+
return result;
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
// Gets object property value.
|
|
2237
|
+
napi_value NodeApiJsiRuntime::getProperty(napi_value object, napi_value propertyId) const {
|
|
2238
|
+
napi_value result{};
|
|
2239
|
+
CHECK_NAPI(jsrApi_->napi_get_property(env_, object, propertyId, &result));
|
|
2240
|
+
return result;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
// Sets object property value.
|
|
2244
|
+
void NodeApiJsiRuntime::setProperty(napi_value object, napi_value propertyId, napi_value value) const {
|
|
2245
|
+
CHECK_NAPI(jsrApi_->napi_set_property(env_, object, propertyId, value));
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
// Sets object property value with the provided property accessibility attributes.
|
|
2249
|
+
void NodeApiJsiRuntime::setProperty(
|
|
2250
|
+
napi_value object,
|
|
2251
|
+
napi_value propertyId,
|
|
2252
|
+
napi_value value,
|
|
2253
|
+
napi_property_attributes attrs) const {
|
|
2254
|
+
napi_property_descriptor descriptor{};
|
|
2255
|
+
descriptor.name = propertyId;
|
|
2256
|
+
descriptor.value = value;
|
|
2257
|
+
descriptor.attributes = attrs;
|
|
2258
|
+
CHECK_NAPI(jsrApi_->napi_define_properties(env_, object, 1, &descriptor));
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
// Creates a new JavaScript Array with the provided length.
|
|
2262
|
+
napi_value NodeApiJsiRuntime::createNodeApiArray(size_t length) const {
|
|
2263
|
+
napi_value result{};
|
|
2264
|
+
CHECK_NAPI(jsrApi_->napi_create_array_with_length(env_, length, &result));
|
|
2265
|
+
return result;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
bool NodeApiJsiRuntime::isArray(napi_value value) const {
|
|
2269
|
+
bool result{};
|
|
2270
|
+
CHECK_NAPI(jsrApi_->napi_is_array(env_, value, &result));
|
|
2271
|
+
return result;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
size_t NodeApiJsiRuntime::getArrayLength(napi_value value) const {
|
|
2275
|
+
uint32_t result{};
|
|
2276
|
+
CHECK_NAPI(jsrApi_->napi_get_array_length(env_, value, &result));
|
|
2277
|
+
return result;
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
napi_value NodeApiJsiRuntime::getElement(napi_value arr, size_t index) const {
|
|
2281
|
+
napi_value result{};
|
|
2282
|
+
CHECK_NAPI(jsrApi_->napi_get_element(env_, arr, static_cast<int32_t>(index), &result));
|
|
2283
|
+
return result;
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
// Sets array element.
|
|
2287
|
+
void NodeApiJsiRuntime::setElement(napi_value array, uint32_t index, napi_value value) const {
|
|
2288
|
+
CHECK_NAPI(jsrApi_->napi_set_element(env_, array, index, value));
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
// The NAPI external function callback used for the JSI host function implementation.
|
|
2292
|
+
/*static*/ napi_value __cdecl NodeApiJsiRuntime::jsiHostFunctionCallback(
|
|
2293
|
+
napi_env env,
|
|
2294
|
+
napi_callback_info info) noexcept {
|
|
2295
|
+
HostFunctionWrapper *hostFuncWrapper{};
|
|
2296
|
+
size_t argc{};
|
|
2297
|
+
CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
|
|
2298
|
+
env, info, &argc, nullptr, nullptr, reinterpret_cast<void **>(&hostFuncWrapper)));
|
|
2299
|
+
CHECK_ELSE_CRASH(hostFuncWrapper, "Cannot find the host function");
|
|
2300
|
+
NodeApiJsiRuntime &runtime = hostFuncWrapper->runtime();
|
|
2301
|
+
NodeApiPointerValueScope scope{runtime};
|
|
2302
|
+
|
|
2303
|
+
return runtime.handleCallbackExceptions([&env, &info, &argc, &runtime, &hostFuncWrapper]() {
|
|
2304
|
+
SmallBuffer<napi_value, MaxStackArgCount> napiArgs(argc);
|
|
2305
|
+
napi_value thisArg{};
|
|
2306
|
+
CHECK_NAPI_ELSE_CRASH(
|
|
2307
|
+
JSRuntimeApi::current()->napi_get_cb_info(env, info, &argc, napiArgs.data(), &thisArg, nullptr));
|
|
2308
|
+
CHECK_ELSE_CRASH(napiArgs.size() == argc, "Wrong argument count");
|
|
2309
|
+
const JsiValueView jsiThisArg{&runtime, thisArg};
|
|
2310
|
+
JsiValueViewArgs jsiArgs(&runtime, span<napi_value>(napiArgs.data(), napiArgs.size()));
|
|
2311
|
+
|
|
2312
|
+
const jsi::HostFunctionType &hostFunc = hostFuncWrapper->hostFunction();
|
|
2313
|
+
return runtime.runInMethodContext("HostFunction", [&hostFunc, &runtime, &jsiThisArg, &jsiArgs]() {
|
|
2314
|
+
return runtime.getNodeApiValue(hostFunc(runtime, jsiThisArg, jsiArgs.data(), jsiArgs.size()));
|
|
2315
|
+
});
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
// Creates an external function.
|
|
2320
|
+
napi_value NodeApiJsiRuntime::createExternalFunction(
|
|
2321
|
+
napi_value name,
|
|
2322
|
+
int32_t paramCount,
|
|
2323
|
+
napi_callback callback,
|
|
2324
|
+
void *callbackData) {
|
|
2325
|
+
std::string funcName = stringToStdString(name);
|
|
2326
|
+
napi_value function{};
|
|
2327
|
+
CHECK_NAPI(
|
|
2328
|
+
jsrApi_->napi_create_function(env_, funcName.data(), funcName.length(), callback, callbackData, &function));
|
|
2329
|
+
setProperty(
|
|
2330
|
+
function, getNodeApiValue(propertyId_.length), createInt32(paramCount), napi_property_attributes::napi_default);
|
|
2331
|
+
|
|
2332
|
+
return function;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
// Creates an object that wraps up external data.
|
|
2336
|
+
napi_value NodeApiJsiRuntime::createExternalObject(void *data, napi_finalize finalizeCallback) const {
|
|
2337
|
+
napi_value result{};
|
|
2338
|
+
CHECK_NAPI(jsrApi_->napi_create_external(env_, data, finalizeCallback, nullptr, &result));
|
|
2339
|
+
return result;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
// Wraps up std::unique_ptr as an external object.
|
|
2343
|
+
template <typename T>
|
|
2344
|
+
napi_value NodeApiJsiRuntime::createExternalObject(std::unique_ptr<T> &&data) const {
|
|
2345
|
+
napi_finalize finalize = [](napi_env /*env*/, void *dataToDestroy, void * /*finalizerHint*/) {
|
|
2346
|
+
// We wrap dataToDestroy in a unique_ptr to avoid calling delete explicitly.
|
|
2347
|
+
std::unique_ptr<T> dataDeleter{static_cast<T *>(dataToDestroy)};
|
|
2348
|
+
};
|
|
2349
|
+
napi_value object = createExternalObject(data.get(), finalize);
|
|
2350
|
+
|
|
2351
|
+
// We only call data.release() after the createExternalObject succeeds.
|
|
2352
|
+
// Otherwise, when createExternalObject fails and an exception is thrown,
|
|
2353
|
+
// the memory that data used to own will be leaked.
|
|
2354
|
+
data.release();
|
|
2355
|
+
return object;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
// Gets external data wrapped by an external object.
|
|
2359
|
+
void *NodeApiJsiRuntime::getExternalData(napi_value object) const {
|
|
2360
|
+
void *result{};
|
|
2361
|
+
CHECK_NAPI(jsrApi_->napi_get_value_external(env_, object, &result));
|
|
2362
|
+
return result;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
// Gets JSI host object wrapped into a napi_value object.
|
|
2366
|
+
const std::shared_ptr<jsi::HostObject> &NodeApiJsiRuntime::getJsiHostObject(napi_value obj) {
|
|
2367
|
+
const napi_value hostObjectHolder = getProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol));
|
|
2368
|
+
|
|
2369
|
+
if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
|
|
2370
|
+
if (void *data = getExternalData(hostObjectHolder)) {
|
|
2371
|
+
return *static_cast<std::shared_ptr<jsi::HostObject> *>(data);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
throw jsi::JSINativeException("Cannot get HostObjects.");
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
// Gets cached or creates Proxy handler to implement the JSI host object.
|
|
2379
|
+
napi_value NodeApiJsiRuntime::getHostObjectProxyHandler() {
|
|
2380
|
+
if (!cachedValue_.HostObjectProxyHandler) {
|
|
2381
|
+
const napi_value handler = createNodeApiObject();
|
|
2382
|
+
setProxyTrap<&NodeApiJsiRuntime::hostObjectHasTrap, 2>(handler, getNodeApiValue(propertyId_.has));
|
|
2383
|
+
setProxyTrap<&NodeApiJsiRuntime::hostObjectGetTrap, 3>(handler, getNodeApiValue(propertyId_.get));
|
|
2384
|
+
setProxyTrap<&NodeApiJsiRuntime::hostObjectSetTrap, 4>(handler, getNodeApiValue(propertyId_.set));
|
|
2385
|
+
setProxyTrap<&NodeApiJsiRuntime::hostObjectOwnKeysTrap, 1>(handler, getNodeApiValue(propertyId_.ownKeys));
|
|
2386
|
+
setProxyTrap<&NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap, 2>(
|
|
2387
|
+
handler, getNodeApiValue(propertyId_.getOwnPropertyDescriptor));
|
|
2388
|
+
cachedValue_.HostObjectProxyHandler = makeNodeApiRef(handler, NodeApiPointerValueKind::Object);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
return getNodeApiValue(cachedValue_.HostObjectProxyHandler);
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
// Sets Proxy trap method as a pointer to NodeApiJsiRuntime instance method.
|
|
2395
|
+
template <napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>), size_t argCount>
|
|
2396
|
+
void NodeApiJsiRuntime::setProxyTrap(napi_value handler, napi_value propertyName) {
|
|
2397
|
+
napi_callback proxyTrap = [](napi_env env, napi_callback_info info) noexcept {
|
|
2398
|
+
NodeApiJsiRuntime *runtime{};
|
|
2399
|
+
napi_value args[argCount]{};
|
|
2400
|
+
size_t actualArgCount{argCount};
|
|
2401
|
+
CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
|
|
2402
|
+
env, info, &actualArgCount, args, nullptr, reinterpret_cast<void **>(&runtime)));
|
|
2403
|
+
CHECK_ELSE_CRASH(actualArgCount == argCount, "proxy trap requires argCount arguments.");
|
|
2404
|
+
NodeApiPointerValueScope scope{*runtime};
|
|
2405
|
+
return runtime->handleCallbackExceptions(
|
|
2406
|
+
[&runtime, &args]() { return (runtime->*trapMethod)(span<napi_value>(args, argCount)); });
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2409
|
+
setProperty(handler, propertyName, createExternalFunction(propertyName, argCount, proxyTrap, this));
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
// The host object Proxy 'has' trap implementation.
|
|
2413
|
+
napi_value NodeApiJsiRuntime::hostObjectHasTrap(span<napi_value> args) {
|
|
2414
|
+
// args[0] - the Proxy target object.
|
|
2415
|
+
// args[1] - the name of the property to check.
|
|
2416
|
+
napi_value propertyName = args[1];
|
|
2417
|
+
const auto &hostObject = getJsiHostObject(args[0]);
|
|
2418
|
+
return runInMethodContext("HostObject::has", [&hostObject, &propertyName, this]() {
|
|
2419
|
+
// std::vector<jsi::PropNameID> ownKeys = hostObject->getPropertyNames(*this);
|
|
2420
|
+
// for (jsi::PropNameID &ownKey : ownKeys) {
|
|
2421
|
+
// if (strictEquals(propertyName, getNodeApiValue(ownKey))) {
|
|
2422
|
+
return getBoolean(true);
|
|
2423
|
+
// }
|
|
2424
|
+
// }
|
|
2425
|
+
// return getBoolean(false);
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
// The host object Proxy 'get' trap implementation.
|
|
2430
|
+
napi_value NodeApiJsiRuntime::hostObjectGetTrap(span<napi_value> args) {
|
|
2431
|
+
// args[0] - the Proxy target object.
|
|
2432
|
+
// args[1] - the name of the property to set.
|
|
2433
|
+
// args[2] - the Proxy object (unused).
|
|
2434
|
+
napi_value target = args[0];
|
|
2435
|
+
napi_value propertyName = args[1];
|
|
2436
|
+
bool isTargetOwnProp{};
|
|
2437
|
+
CHECK_NAPI(jsrApi_->napi_has_own_property(env_, target, propertyName, &isTargetOwnProp));
|
|
2438
|
+
if (isTargetOwnProp) {
|
|
2439
|
+
return getProperty(target, propertyName);
|
|
2440
|
+
}
|
|
2441
|
+
const auto &hostObject = getJsiHostObject(args[0]);
|
|
2442
|
+
PropNameIDView propertyId{this, propertyName};
|
|
2443
|
+
return runInMethodContext("HostObject::get", [&hostObject, &propertyId, this]() {
|
|
2444
|
+
return getNodeApiValue(hostObject->get(*this, propertyId));
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
// The host object Proxy 'set' trap implementation.
|
|
2449
|
+
napi_value NodeApiJsiRuntime::hostObjectSetTrap(span<napi_value> args) {
|
|
2450
|
+
// args[0] - the Proxy target object.
|
|
2451
|
+
// args[1] - the name of the property to set.
|
|
2452
|
+
// args[2] - the new value of the property to set.
|
|
2453
|
+
// args[3] - the Proxy object (unused).
|
|
2454
|
+
const auto &hostObject = getJsiHostObject(args[0]);
|
|
2455
|
+
PropNameIDView propertyId{this, args[1]};
|
|
2456
|
+
JsiValueView value{this, args[2]};
|
|
2457
|
+
runInMethodContext(
|
|
2458
|
+
"HostObject::set", [&hostObject, &propertyId, &value, this]() { hostObject->set(*this, propertyId, value); });
|
|
2459
|
+
return getUndefined();
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
// The host object Proxy 'ownKeys' trap implementation.
|
|
2463
|
+
napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
|
|
2464
|
+
// args[0] - the Proxy target object.
|
|
2465
|
+
napi_value target = args[0];
|
|
2466
|
+
|
|
2467
|
+
napi_value targetOwnKeys{};
|
|
2468
|
+
CHECK_NAPI(jsrApi_->napi_get_all_property_names(
|
|
2469
|
+
env_, target, napi_key_own_only, napi_key_all_properties, napi_key_numbers_to_strings, &targetOwnKeys));
|
|
2470
|
+
CHECK_ELSE_THROW(isArray(targetOwnKeys), "Expected an array");
|
|
2471
|
+
size_t targetOwnKeysLength = getArrayLength(targetOwnKeys);
|
|
2472
|
+
|
|
2473
|
+
const auto &hostObject = getJsiHostObject(target);
|
|
2474
|
+
std::vector<jsi::PropNameID> hostOwnKeys = runInMethodContext(
|
|
2475
|
+
"HostObject::getPropertyNames", [&hostObject, this]() { return hostObject->getPropertyNames(*this); });
|
|
2476
|
+
|
|
2477
|
+
std::vector<jsi::PropNameID> ownKeys;
|
|
2478
|
+
std::unordered_set<const PointerValue *> uniqueOwnKeys;
|
|
2479
|
+
// Minus one hostObjectSymbol key.
|
|
2480
|
+
ownKeys.reserve(targetOwnKeysLength - 1 + hostOwnKeys.size());
|
|
2481
|
+
uniqueOwnKeys.reserve(targetOwnKeysLength - 1 + hostOwnKeys.size());
|
|
2482
|
+
|
|
2483
|
+
// Read all target own keys.
|
|
2484
|
+
if (targetOwnKeysLength > 1) {
|
|
2485
|
+
auto addPropNameId = [this, &uniqueOwnKeys, &ownKeys](jsi::PropNameID &&propNameId) {
|
|
2486
|
+
const PointerValue *pv = getPointerValue(propNameId);
|
|
2487
|
+
auto inserted = uniqueOwnKeys.insert(pv);
|
|
2488
|
+
CHECK_ELSE_THROW(inserted.second, "Target has non-unique keys");
|
|
2489
|
+
ownKeys.push_back(std::move(propNameId));
|
|
2490
|
+
};
|
|
2491
|
+
for (size_t i = 0; i < targetOwnKeysLength; ++i) {
|
|
2492
|
+
napi_value key = getElement(targetOwnKeys, i);
|
|
2493
|
+
napi_valuetype keyType = typeOf(key);
|
|
2494
|
+
if (keyType == napi_string) {
|
|
2495
|
+
addPropNameId(createPropNameIDFromString(makeJsiPointer<jsi::String>(key)));
|
|
2496
|
+
#if JSI_VERSION >= 8
|
|
2497
|
+
} else if (keyType == napi_symbol) {
|
|
2498
|
+
if (strictEquals(key, getNodeApiValue(propertyId_.hostObjectSymbol))) {
|
|
2499
|
+
continue;
|
|
2500
|
+
}
|
|
2501
|
+
addPropNameId(createPropNameIDFromSymbol(makeJsiPointer<jsi::Symbol>(key)));
|
|
2502
|
+
#endif
|
|
2503
|
+
} else {
|
|
2504
|
+
throwNativeException("Unexpected key type");
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
// Read all unique host own keys.
|
|
2510
|
+
for (jsi::PropNameID &propNameId : hostOwnKeys) {
|
|
2511
|
+
const PointerValue *pv = getPointerValue(propNameId);
|
|
2512
|
+
auto inserted = uniqueOwnKeys.insert(pv);
|
|
2513
|
+
if (inserted.second) {
|
|
2514
|
+
ownKeys.push_back(std::move(propNameId));
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// Put indexed properties before named ones.
|
|
2519
|
+
struct Index {
|
|
2520
|
+
uint32_t index;
|
|
2521
|
+
napi_value value;
|
|
2522
|
+
};
|
|
2523
|
+
std::vector<Index> indexKeys;
|
|
2524
|
+
std::vector<napi_value> nonIndexKeys;
|
|
2525
|
+
nonIndexKeys.reserve(ownKeys.size());
|
|
2526
|
+
for (const jsi::PropNameID &key : ownKeys) {
|
|
2527
|
+
napi_value napiKey = getNodeApiValue(key);
|
|
2528
|
+
napi_valuetype valueType = typeOf(napiKey);
|
|
2529
|
+
if (valueType == napi_string) {
|
|
2530
|
+
std::string keyStr = stringToStdString(napiKey);
|
|
2531
|
+
std::optional<uint32_t> indexKey = toArrayIndex(keyStr.begin(), keyStr.end());
|
|
2532
|
+
if (indexKey.has_value()) {
|
|
2533
|
+
indexKeys.push_back(Index{indexKey.value(), napiKey});
|
|
2534
|
+
continue;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
nonIndexKeys.push_back(napiKey);
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
std::sort(indexKeys.begin(), indexKeys.end(), [](const Index &left, const Index &right) {
|
|
2541
|
+
return left.index < right.index;
|
|
2542
|
+
});
|
|
2543
|
+
|
|
2544
|
+
napi_value ownKeyArray = createNodeApiArray(0);
|
|
2545
|
+
uint32_t index = 0;
|
|
2546
|
+
for (const Index &indexKey : indexKeys) {
|
|
2547
|
+
setElement(ownKeyArray, index++, indexKey.value);
|
|
2548
|
+
}
|
|
2549
|
+
for (napi_value napiKey : nonIndexKeys) {
|
|
2550
|
+
setElement(ownKeyArray, index++, napiKey);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
return ownKeyArray;
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
// The host object Proxy 'getOwnPropertyDescriptor' trap implementation.
|
|
2557
|
+
napi_value NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap(span<napi_value> args) {
|
|
2558
|
+
// args[0] - the Proxy target object.
|
|
2559
|
+
// args[1] - the property
|
|
2560
|
+
const auto &hostObject = getJsiHostObject(args[0]);
|
|
2561
|
+
PropNameIDView propertyId{this, args[1]};
|
|
2562
|
+
|
|
2563
|
+
return runInMethodContext("HostObject::getOwnPropertyDescriptor", [&hostObject, &propertyId, this]() {
|
|
2564
|
+
auto getPropDescriptor = [](napi_value name, napi_value value) {
|
|
2565
|
+
return napi_property_descriptor{
|
|
2566
|
+
nullptr, name, nullptr, nullptr, nullptr, value, napi_default_jsproperty, nullptr};
|
|
2567
|
+
};
|
|
2568
|
+
napi_value trueValue = getBoolean(true);
|
|
2569
|
+
napi_property_descriptor properties[]{
|
|
2570
|
+
getPropDescriptor(getNodeApiValue(propertyId_.value), getNodeApiValue(hostObject->get(*this, propertyId))),
|
|
2571
|
+
getPropDescriptor(getNodeApiValue(propertyId_.writable), trueValue),
|
|
2572
|
+
getPropDescriptor(getNodeApiValue(propertyId_.enumerable), trueValue),
|
|
2573
|
+
getPropDescriptor(getNodeApiValue(propertyId_.configurable), trueValue)};
|
|
2574
|
+
napi_value descriptor = createNodeApiObject();
|
|
2575
|
+
CHECK_NAPI(jsrApi_->napi_define_properties(env_, descriptor, std::size(properties), properties));
|
|
2576
|
+
return descriptor;
|
|
2577
|
+
});
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
// Converts jsi::Bufer to span.
|
|
2581
|
+
span<const uint8_t> NodeApiJsiRuntime::toSpan(const jsi::Buffer &buffer) {
|
|
2582
|
+
return span<const uint8_t>(buffer.data(), buffer.size());
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
// Creates jsi::Value from napi_value.
|
|
2586
|
+
jsi::Value NodeApiJsiRuntime::toJsiValue(napi_value value) const {
|
|
2587
|
+
switch (typeOf(value)) {
|
|
2588
|
+
case napi_valuetype::napi_undefined:
|
|
2589
|
+
return jsi::Value::undefined();
|
|
2590
|
+
case napi_valuetype::napi_null:
|
|
2591
|
+
return jsi::Value::null();
|
|
2592
|
+
case napi_valuetype::napi_boolean:
|
|
2593
|
+
return jsi::Value{getValueBool(value)};
|
|
2594
|
+
case napi_valuetype::napi_number:
|
|
2595
|
+
return jsi::Value{getValueDouble(value)};
|
|
2596
|
+
case napi_valuetype::napi_string:
|
|
2597
|
+
return jsi::Value{makeJsiPointer<jsi::String>(value)};
|
|
2598
|
+
case napi_valuetype::napi_symbol:
|
|
2599
|
+
return jsi::Value{makeJsiPointer<jsi::Symbol>(value)};
|
|
2600
|
+
case napi_valuetype::napi_object:
|
|
2601
|
+
case napi_valuetype::napi_function:
|
|
2602
|
+
case napi_valuetype::napi_external:
|
|
2603
|
+
return jsi::Value{makeJsiPointer<jsi::Object>(value)};
|
|
2604
|
+
#if JSI_VERSION >= 6
|
|
2605
|
+
case napi_valuetype::napi_bigint:
|
|
2606
|
+
return jsi::Value{makeJsiPointer<jsi::BigInt>(value)};
|
|
2607
|
+
#endif
|
|
2608
|
+
default:
|
|
2609
|
+
throw jsi::JSINativeException("Unexpected value type");
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Value &value) const {
|
|
2614
|
+
if (value.isUndefined()) {
|
|
2615
|
+
return getUndefined();
|
|
2616
|
+
} else if (value.isNull()) {
|
|
2617
|
+
return getNull();
|
|
2618
|
+
} else if (value.isBool()) {
|
|
2619
|
+
return getBoolean(value.getBool());
|
|
2620
|
+
} else if (value.isNumber()) {
|
|
2621
|
+
return createDouble(value.getNumber());
|
|
2622
|
+
} else if (value.isSymbol()) {
|
|
2623
|
+
return getNodeApiValue(value.getSymbol(*const_cast<NodeApiJsiRuntime *>(this)));
|
|
2624
|
+
} else if (value.isString()) {
|
|
2625
|
+
return getNodeApiValue(value.getString(*const_cast<NodeApiJsiRuntime *>(this)));
|
|
2626
|
+
} else if (value.isObject()) {
|
|
2627
|
+
return getNodeApiValue(value.getObject(*const_cast<NodeApiJsiRuntime *>(this)));
|
|
2628
|
+
#if JSI_VERSION >= 8
|
|
2629
|
+
} else if (value.isBigInt()) {
|
|
2630
|
+
return getNodeApiValue(value.getBigInt(*const_cast<NodeApiJsiRuntime *>(this)));
|
|
2631
|
+
#endif
|
|
2632
|
+
} else {
|
|
2633
|
+
throw jsi::JSINativeException("Unexpected jsi::Value type");
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Pointer &ptr) const {
|
|
2638
|
+
return const_cast<NodeApiPointerValue *>(static_cast<const NodeApiPointerValue *>(getPointerValue(ptr)))
|
|
2639
|
+
->getValue(*const_cast<NodeApiJsiRuntime *>(this));
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
napi_value NodeApiJsiRuntime::getNodeApiValue(const NodeApiRefHolder &ref) const {
|
|
2643
|
+
return ref->getValue(*const_cast<NodeApiJsiRuntime *>(this));
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::cloneNodeApiPointerValue(
|
|
2647
|
+
const PointerValue *pointerValue) {
|
|
2648
|
+
return static_cast<const NodeApiPointerValue *>(pointerValue)->clone(*this);
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// Adopted from Hermes code.
|
|
2652
|
+
std::optional<uint32_t> NodeApiJsiRuntime::toArrayIndex(
|
|
2653
|
+
std::string::const_iterator first,
|
|
2654
|
+
std::string::const_iterator last) {
|
|
2655
|
+
// Empty string is invalid.
|
|
2656
|
+
if (first == last)
|
|
2657
|
+
return std::nullopt;
|
|
2658
|
+
|
|
2659
|
+
// Leading 0 is special.
|
|
2660
|
+
if (*first == '0') {
|
|
2661
|
+
++first;
|
|
2662
|
+
// Just "0"?
|
|
2663
|
+
if (first == last)
|
|
2664
|
+
return 0;
|
|
2665
|
+
// Leading 0 is invalid otherwise.
|
|
2666
|
+
return std::nullopt;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
uint32_t res = 0;
|
|
2670
|
+
do {
|
|
2671
|
+
auto ch = *first;
|
|
2672
|
+
if (ch < '0' || ch > '9')
|
|
2673
|
+
return std::nullopt;
|
|
2674
|
+
uint64_t tmp = (uint64_t)res * 10 + (ch - '0');
|
|
2675
|
+
// Check for overflow.
|
|
2676
|
+
if (tmp & ((uint64_t)0xFFFFFFFFu << 32))
|
|
2677
|
+
return std::nullopt;
|
|
2678
|
+
res = (uint32_t)tmp;
|
|
2679
|
+
} while (++first != last);
|
|
2680
|
+
|
|
2681
|
+
// 0xFFFFFFFF is not a valid array index.
|
|
2682
|
+
if (res == 0xFFFFFFFFu)
|
|
2683
|
+
return std::nullopt;
|
|
2684
|
+
|
|
2685
|
+
return res;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::Object, T>, int>>
|
|
2689
|
+
T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
|
|
2690
|
+
return make<T>(NodeApiRefCountedPointerValue::make(
|
|
2691
|
+
*const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::Object));
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::String, T>, int>>
|
|
2695
|
+
T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
|
|
2696
|
+
return make<T>(NodeApiRefCountedPointerValue::make(
|
|
2697
|
+
*const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::String));
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int>>
|
|
2701
|
+
T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
|
|
2702
|
+
return make<T>(NodeApiRefCountedPointerValue::make(
|
|
2703
|
+
*const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::Symbol));
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
#if JSI_VERSION >= 6
|
|
2707
|
+
template <typename T, std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int>>
|
|
2708
|
+
T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
|
|
2709
|
+
return make<T>(NodeApiRefCountedPointerValue::make(
|
|
2710
|
+
*const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::BigInt));
|
|
2711
|
+
}
|
|
2712
|
+
#endif
|
|
2713
|
+
|
|
2714
|
+
template <
|
|
2715
|
+
typename TTo,
|
|
2716
|
+
typename TFrom,
|
|
2717
|
+
std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int>,
|
|
2718
|
+
std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int>>
|
|
2719
|
+
TTo NodeApiJsiRuntime::cloneAs(const TFrom &pointer) const {
|
|
2720
|
+
return make<TTo>(static_cast<const NodeApiRefCountedPointerValue *>(getPointerValue(pointer))
|
|
2721
|
+
->clone(*const_cast<NodeApiJsiRuntime *>(this)));
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
NodeApiJsiRuntime::NodeApiRefHolder NodeApiJsiRuntime::makeNodeApiRef(
|
|
2725
|
+
napi_value value,
|
|
2726
|
+
NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
|
|
2727
|
+
int32_t initialRefCount) {
|
|
2728
|
+
return NodeApiRefHolder(NodeApiRefCountedPointerValue::makeNodeApiRef(*this, value, pointerKind, initialRefCount));
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
void NodeApiJsiRuntime::addStackValue(NodeApiStackValueHolder &&pointerHolder) {
|
|
2732
|
+
if (stackValues_.size() == stackValues_.capacity()) {
|
|
2733
|
+
collectUnusedStackValues();
|
|
2734
|
+
}
|
|
2735
|
+
stackValues_.push_back(std::move(pointerHolder));
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
void NodeApiJsiRuntime::addRef(NodeApiRefHolder &&refHolder) {
|
|
2739
|
+
if (refs_.size() == refs_.capacity()) {
|
|
2740
|
+
collectUnusedRefs();
|
|
2741
|
+
}
|
|
2742
|
+
refs_.push_back(std::move(refHolder));
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
void NodeApiJsiRuntime::pushPointerValueScope() noexcept {
|
|
2746
|
+
stackScopes_.push_back(stackValues_.size());
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
void NodeApiJsiRuntime::popPointerValueScope() noexcept {
|
|
2750
|
+
CHECK_ELSE_CRASH(!stackScopes_.empty(), "There are no scopes to pop");
|
|
2751
|
+
|
|
2752
|
+
size_t newStackSize = stackScopes_.back();
|
|
2753
|
+
auto beginIterator = stackValues_.begin() + newStackSize;
|
|
2754
|
+
stackScopes_.pop_back();
|
|
2755
|
+
std::for_each(beginIterator, stackValues_.end(), [this](NodeApiStackValueHolder &holder) {
|
|
2756
|
+
holder.release()->convertToNodeApiRef(*this);
|
|
2757
|
+
});
|
|
2758
|
+
stackValues_.resize(newStackSize);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
void NodeApiJsiRuntime::collectUnusedStackValues() {
|
|
2762
|
+
auto usedByJsiPointer = [](NodeApiStackValueHolder &holder) {
|
|
2763
|
+
return NodeApiRefCountedPointerValue::usedByJsiPointer(holder.get());
|
|
2764
|
+
};
|
|
2765
|
+
auto beginIterator = stackValues_.begin();
|
|
2766
|
+
for (size_t &scope : stackScopes_) {
|
|
2767
|
+
auto endIterator = stackValues_.begin() + scope;
|
|
2768
|
+
beginIterator = std::partition(beginIterator, endIterator, usedByJsiPointer);
|
|
2769
|
+
scope -= endIterator - beginIterator;
|
|
2770
|
+
}
|
|
2771
|
+
beginIterator = std::partition(beginIterator, stackValues_.end(), usedByJsiPointer);
|
|
2772
|
+
stackValues_.resize(beginIterator - stackValues_.begin());
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
void NodeApiJsiRuntime::collectUnusedRefs() noexcept {
|
|
2776
|
+
auto usedByJsiPointer = [](NodeApiRefHolder &holder) {
|
|
2777
|
+
return NodeApiRefCountedPointerValue::usedByJsiPointer(holder.get());
|
|
2778
|
+
};
|
|
2779
|
+
auto beginIterator = std::partition(refs_.begin(), refs_.end(), usedByJsiPointer);
|
|
2780
|
+
std::for_each(beginIterator, refs_.end(), [this](NodeApiRefHolder &holder) {
|
|
2781
|
+
NodeApiRefCountedPointerValue::deleteNodeApiRef(holder.release(), *this);
|
|
2782
|
+
});
|
|
2783
|
+
refs_.resize(beginIterator - refs_.begin());
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
} // namespace
|
|
2787
|
+
|
|
2788
|
+
std::unique_ptr<jsi::Runtime>
|
|
2789
|
+
makeNodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept {
|
|
2790
|
+
return std::make_unique<NodeApiJsiRuntime>(env, jsrApi, std::move(onDelete));
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
} // namespace Microsoft::NodeApiJsi
|
|
2794
|
+
|
|
2795
|
+
EXTERN_C_START
|
|
2796
|
+
|
|
2797
|
+
// Default implementation of jsr_get_description if it is not provided by JS engine.
|
|
2798
|
+
// It returns "NodeApiJsiRuntime" string.
|
|
2799
|
+
napi_status NAPI_CDECL default_jsr_get_description(napi_env /*env*/, const char **result) {
|
|
2800
|
+
if (result != nullptr) {
|
|
2801
|
+
*result = "NodeApiJsiRuntime";
|
|
2802
|
+
}
|
|
2803
|
+
return napi_ok;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
// Default implementation of jsr_drain_microtasks if it is not provided by JS engine.
|
|
2807
|
+
// It does nothing
|
|
2808
|
+
napi_status NAPI_CDECL default_jsr_drain_microtasks(napi_env /*env*/, int32_t /*max_count_hint*/, bool *result) {
|
|
2809
|
+
if (result != nullptr) {
|
|
2810
|
+
*result = true; // All tasks are drained
|
|
2811
|
+
}
|
|
2812
|
+
return napi_ok;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
// Default implementation of jsr_is_inspectable if it is not provided by JS engine.
|
|
2816
|
+
// It always returns false.
|
|
2817
|
+
napi_status NAPI_CDECL default_jsr_is_inspectable(napi_env /*env*/, bool *result) {
|
|
2818
|
+
if (result != nullptr) {
|
|
2819
|
+
*result = false;
|
|
2820
|
+
}
|
|
2821
|
+
return napi_ok;
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
// Default implementation of jsr_open_napi_env_scope if it is not provided by JS engine.
|
|
2825
|
+
napi_status NAPI_CDECL default_jsr_open_napi_env_scope(napi_env /*env*/, jsr_napi_env_scope * /*scope*/) {
|
|
2826
|
+
return napi_ok;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
// Default implementation of jsr_close_napi_env_scope if it is not provided by JS engine.
|
|
2830
|
+
napi_status NAPI_CDECL default_jsr_close_napi_env_scope(napi_env /*env*/, jsr_napi_env_scope /*scope*/) {
|
|
2831
|
+
return napi_ok;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
// TODO: Ensure that we either load all three functions or use their default versions and never mix and match.
|
|
2835
|
+
|
|
2836
|
+
// Default implementation of jsr_create_prepared_script if it is not provided by JS engine.
|
|
2837
|
+
// It return napi_ref as a jsr_prepared_script that wraps up an object with a "script" property string.
|
|
2838
|
+
napi_status NAPI_CDECL default_jsr_create_prepared_script(
|
|
2839
|
+
napi_env env,
|
|
2840
|
+
const uint8_t *script_data,
|
|
2841
|
+
size_t script_length,
|
|
2842
|
+
jsr_data_delete_cb script_delete_cb,
|
|
2843
|
+
void *deleter_data,
|
|
2844
|
+
const char * /*source_url*/,
|
|
2845
|
+
jsr_prepared_script *result) {
|
|
2846
|
+
Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
|
|
2847
|
+
napi_value script{}, obj{};
|
|
2848
|
+
// Do not use NAPI_CALL - we must finalize the buffer right after we attempted the string creation.
|
|
2849
|
+
napi_status status =
|
|
2850
|
+
jsrApi->napi_create_string_utf8(env, reinterpret_cast<const char *>(script_data), script_length, &script);
|
|
2851
|
+
if (script_delete_cb != nullptr) {
|
|
2852
|
+
script_delete_cb(const_cast<uint8_t *>(script_data), deleter_data);
|
|
2853
|
+
}
|
|
2854
|
+
NAPI_CALL(status);
|
|
2855
|
+
NAPI_CALL(jsrApi->napi_create_object(env, &obj));
|
|
2856
|
+
NAPI_CALL(jsrApi->napi_set_named_property(env, obj, "script", script));
|
|
2857
|
+
return jsrApi->napi_create_reference(env, obj, 1, reinterpret_cast<napi_ref *>(result));
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
// Default implementation of jsr_delete_prepared_script if it is not provided by JS engine.
|
|
2861
|
+
// It deletes prepared_script as a napi_ref.
|
|
2862
|
+
napi_status NAPI_CDECL default_jsr_delete_prepared_script(napi_env env, jsr_prepared_script prepared_script) {
|
|
2863
|
+
Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
|
|
2864
|
+
return jsrApi->napi_delete_reference(env, reinterpret_cast<napi_ref>(prepared_script));
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
// Default implementation of jsr_prepared_script_run if it is not provided by JS engine.
|
|
2868
|
+
// It interprets prepared_script as a napi_ref to an object with a "script" property string.
|
|
2869
|
+
napi_status NAPI_CDECL
|
|
2870
|
+
default_jsr_prepared_script_run(napi_env env, jsr_prepared_script prepared_script, napi_value *result) {
|
|
2871
|
+
Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
|
|
2872
|
+
napi_value obj{}, script{};
|
|
2873
|
+
NAPI_CALL(jsrApi->napi_get_reference_value(env, reinterpret_cast<napi_ref>(prepared_script), &obj));
|
|
2874
|
+
NAPI_CALL(jsrApi->napi_get_named_property(env, obj, "script", &script));
|
|
2875
|
+
return jsrApi->napi_run_script(env, script, result);
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
EXTERN_C_END
|