├── .ado ├── guardian │ └── sdl │ │ └── .gdnbaselines ├── windows-build.yml ├── windows-ci.yml ├── windows-jobs.yml ├── windows-pr.yml └── windows-release.yml ├── .clang-format ├── .editorconfig ├── .github └── policies │ └── resourceManagement.yml ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── LICENSE.jsi.md ├── LICENSE.napi.md ├── LICENSE.v8.md ├── README.md ├── ReactNative.V8Jsi.Windows.nuspec ├── ReactNative.V8Jsi.Windows.targets ├── config.json ├── docs ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── SECURITY.md ├── localbuild.ps1 ├── scripts ├── build.ps1 ├── download_depottools.ps1 ├── fetch_code.ps1 ├── patch │ ├── build.diff │ ├── src.diff │ └── zlib.diff ├── tracing │ └── trace.ps1 └── update_version.ps1 └── src ├── BUILD.gn ├── IsolateData.h ├── MurmurHash.cpp ├── MurmurHash.h ├── V8Instrumentation.cpp ├── V8Instrumentation.h ├── V8JsiRuntime.cpp ├── V8JsiRuntime_impl.h ├── V8Windows.h ├── etw ├── tracing.cpp ├── tracing.h └── tracing.man ├── inspector ├── LICENSE_LLHTTP ├── LICENSE_NODE ├── inspector_agent.cpp ├── inspector_agent.h ├── inspector_socket.cpp ├── inspector_socket.h ├── inspector_socket_server.cpp ├── inspector_socket_server.h ├── inspector_tcp.cpp ├── inspector_tcp.h ├── inspector_utils.cpp ├── inspector_utils.h ├── llhttp.c ├── llhttp.h ├── llhttp_api.c └── llhttp_http.c ├── jsi ├── .clang-format ├── CMakeLists.txt ├── JSIDynamic.cpp ├── JSIDynamic.h ├── README.md ├── decorator.h ├── instrumentation.h ├── jsi-inl.h ├── jsi.cpp ├── jsi.h ├── jsilib-posix.cpp ├── jsilib-windows.cpp ├── jsilib.h ├── test │ ├── testlib.cpp │ ├── testlib.h │ └── testlib_ext.cpp └── threadsafe.h ├── makev8jsi.lst ├── node-api-jsi ├── ApiLoaders │ ├── JSRuntimeApi.cpp │ ├── JSRuntimeApi.h │ ├── JSRuntimeApi.inc │ ├── NodeApi.cpp │ ├── NodeApi.h │ ├── NodeApi.inc │ ├── NodeApi_posix.cpp │ ├── NodeApi_win.cpp │ ├── V8Api.cpp │ ├── V8Api.h │ └── V8Api.inc ├── NodeApiJsiRuntime.cpp └── NodeApiJsiRuntime.h ├── node-api ├── .clang-format ├── Readme.md ├── env-inl.h ├── js_native_api.h ├── js_native_api_types.h ├── js_native_api_v8.cc ├── js_native_api_v8.h ├── js_native_api_v8_internals.h ├── js_runtime_api.h ├── test │ ├── BUILD.gn │ ├── child_process.cpp │ ├── child_process.h │ ├── js-native-api │ │ ├── .gitignore │ │ ├── 2_function_arguments │ │ │ ├── 2_function_arguments.c │ │ │ ├── binding.gyp │ │ │ └── test.js │ │ ├── 3_callbacks │ │ │ ├── 3_callbacks.c │ │ │ ├── binding.gyp │ │ │ └── test.js │ │ ├── 4_object_factory │ │ │ ├── 4_object_factory.c │ │ │ ├── binding.gyp │ │ │ └── test.js │ │ ├── 5_function_factory │ │ │ ├── 5_function_factory.c │ │ │ ├── binding.gyp │ │ │ └── test.js │ │ ├── 6_object_wrap │ │ │ ├── 6_object_wrap.cc │ │ │ ├── binding.gyp │ │ │ ├── myobject.h │ │ │ ├── test-object-wrap-ref.js │ │ │ └── test.js │ │ ├── 7_factory_wrap │ │ │ ├── 7_factory_wrap.cc │ │ │ ├── binding.gyp │ │ │ ├── myobject.cc │ │ │ ├── myobject.h │ │ │ └── test.js │ │ ├── 8_passing_wrapped │ │ │ ├── 8_passing_wrapped.cc │ │ │ ├── binding.gyp │ │ │ ├── myobject.cc │ │ │ ├── myobject.h │ │ │ └── test.js │ │ ├── common-inl.h │ │ ├── common.h │ │ ├── common │ │ │ ├── assert.js │ │ │ └── common.js │ │ ├── entry_point.h │ │ ├── node_api.h │ │ ├── node_api_types.h │ │ ├── test_array │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_array.c │ │ ├── test_bigint │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_bigint.c │ │ ├── test_cannot_run_js │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_cannot_run_js.c │ │ ├── test_constructor │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test2.js │ │ │ ├── test_constructor.c │ │ │ ├── test_null.c │ │ │ ├── test_null.h │ │ │ └── test_null.js │ │ ├── test_conversions │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_conversions.c │ │ │ ├── test_null.c │ │ │ └── test_null.h │ │ ├── test_dataview │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_dataview.c │ │ ├── test_date │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_date.c │ │ ├── test_error │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_error.c │ │ ├── test_exception │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── testFinalizerException.js │ │ │ └── test_exception.c │ │ ├── test_finalizer │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_fatal_finalize.js │ │ │ └── test_finalizer.c │ │ ├── test_function │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_function.c │ │ ├── test_general │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── testEnvCleanup.js │ │ │ ├── testFinalizer.js │ │ │ ├── testGlobals.js │ │ │ ├── testInstanceOf.js │ │ │ ├── testNapiRun.js │ │ │ ├── testNapiStatus.js │ │ │ └── test_general.c │ │ ├── test_handle_scope │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_handle_scope.c │ │ ├── test_instance_data │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_instance_data.c │ │ ├── test_new_target │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_new_target.c │ │ ├── test_number │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_null.c │ │ │ ├── test_null.h │ │ │ ├── test_null.js │ │ │ └── test_number.c │ │ ├── test_object │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_exceptions.c │ │ │ ├── test_exceptions.js │ │ │ ├── test_null.c │ │ │ ├── test_null.h │ │ │ ├── test_null.js │ │ │ └── test_object.c │ │ ├── test_promise │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_promise.c │ │ ├── test_properties │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_properties.c │ │ ├── test_reference │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_finalizer.c │ │ │ ├── test_finalizer.js │ │ │ └── test_reference.c │ │ ├── test_reference_double_free │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_reference_double_free.c │ │ │ └── test_wrap.js │ │ ├── test_string │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ ├── test_null.c │ │ │ ├── test_null.h │ │ │ ├── test_null.js │ │ │ └── test_string.c │ │ ├── test_symbol │ │ │ ├── binding.gyp │ │ │ ├── test1.js │ │ │ ├── test2.js │ │ │ ├── test3.js │ │ │ └── test_symbol.c │ │ └── test_typedarray │ │ │ ├── binding.gyp │ │ │ ├── test.js │ │ │ └── test_typedarray.c │ ├── node_api_test.cpp │ ├── node_api_test.h │ ├── node_api_test_v8.cpp │ └── testmain.cpp ├── util-inl.h └── v8_api.cpp ├── public ├── Readme.md ├── ScriptStore.h ├── V8JsiRuntime.h ├── compat.h └── v8_api.h ├── source_link.json ├── testmain.cpp └── version.rc /.ado/guardian/sdl/.gdnbaselines: -------------------------------------------------------------------------------- 1 | { 2 | "hydrated": false, 3 | "properties": { 4 | "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines", 5 | "hydrationStatus": "This file does not contain identifying data. It is safe to check into your repo. To hydrate this file with identifying data, run `guardian hydrate --help` and follow the guidance." 6 | }, 7 | "version": "1.0.0", 8 | "baselines": { 9 | "guardian-baseline": { 10 | "name": "guardian-baseline", 11 | "createdDate": "2023-10-21 02:08:05Z", 12 | "lastUpdatedDate": "2023-10-21 02:08:05Z" 13 | } 14 | }, 15 | "results": { 16 | "0c9bea3e0ba4ec1f9f412df1d9116cda3781b5f120c9c268bb38c53a60873a6b": { 17 | "signature": "0c9bea3e0ba4ec1f9f412df1d9116cda3781b5f120c9c268bb38c53a60873a6b", 18 | "alternativeSignatures": [ 19 | "d388e5517024dc10e219f9ca342f0884e28b46aae2e92b5537e52fe93e7440c4" 20 | ], 21 | "memberOf": [ 22 | "guardian-baseline" 23 | ], 24 | "createdDate": "2023-10-21 02:08:05Z" 25 | }, 26 | "844ac8bd279863c0714bef8a8d5458a853e1d7d0afcd6f8fb042c895af9b9c99": { 27 | "signature": "844ac8bd279863c0714bef8a8d5458a853e1d7d0afcd6f8fb042c895af9b9c99", 28 | "alternativeSignatures": [ 29 | "de276c1956f6cad7acc9765c7a1127a126d525b45cf9f6a7ce277a47997a7fdc" 30 | ], 31 | "memberOf": [ 32 | "guardian-baseline" 33 | ], 34 | "createdDate": "2023-10-21 02:08:05Z" 35 | }, 36 | "2133282a9767561d4a3199f40d102d50c276a40c713ff51873b15b4ccc2528e2": { 37 | "signature": "2133282a9767561d4a3199f40d102d50c276a40c713ff51873b15b4ccc2528e2", 38 | "alternativeSignatures": [ 39 | "ceb49633d687c3be368840b3302478e053bb885169e33ae4584c212ef0ca96ae" 40 | ], 41 | "memberOf": [ 42 | "guardian-baseline" 43 | ], 44 | "createdDate": "2023-10-21 02:08:05Z" 45 | }, 46 | "a635e094fa0297b9c8c002484e334ecce0e66ec494a15ccf740ff74c74820e9b": { 47 | "signature": "a635e094fa0297b9c8c002484e334ecce0e66ec494a15ccf740ff74c74820e9b", 48 | "alternativeSignatures": [ 49 | "b83062005ae1d65bfaa76c66029ecb5b21395b435db7e98f0a50f2bb9ad8725a" 50 | ], 51 | "memberOf": [ 52 | "guardian-baseline" 53 | ], 54 | "createdDate": "2023-10-21 02:08:05Z" 55 | }, 56 | "ed3f0398be556ba4a84a6b2e4d664c79f345adfb13f6a6a284ed7cd341b28dc5": { 57 | "signature": "ed3f0398be556ba4a84a6b2e4d664c79f345adfb13f6a6a284ed7cd341b28dc5", 58 | "alternativeSignatures": [ 59 | "920e5ba1bfb73b3cdd3865260c2aa6d1d541b45f2811d8e7a83ef65f9346dc68" 60 | ], 61 | "memberOf": [ 62 | "guardian-baseline" 63 | ], 64 | "createdDate": "2023-10-21 02:08:05Z" 65 | }, 66 | "8601ac212ffa5688ac5bd7c90c88c6821801db1c12aaa238bf8f0b5ddb997cb8": { 67 | "signature": "8601ac212ffa5688ac5bd7c90c88c6821801db1c12aaa238bf8f0b5ddb997cb8", 68 | "alternativeSignatures": [ 69 | "e2056c1150375f38dc46635a15a0ed40c3c626ff43e433d5c16f03b72d22934e" 70 | ], 71 | "memberOf": [ 72 | "guardian-baseline" 73 | ], 74 | "createdDate": "2023-10-21 02:08:05Z" 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /.ado/windows-ci.yml: -------------------------------------------------------------------------------- 1 | name: v8jsi_ci_0.0.$(Date:yyMM.d)$(Rev:rrr) 2 | 3 | # The triggers are overridden by the ADO pipeline definitions. 4 | trigger: none 5 | pr: none 6 | 7 | variables: 8 | - group: V8-Jsi Secrets 9 | - name: ArtifactServices.Symbol.AccountName 10 | value: microsoft 11 | - name: ArtifactServices.Symbol.PAT 12 | value: $(pat-symbols-publish-microsoft) 13 | - name: tags 14 | value: production,externalfacing 15 | 16 | extends: 17 | template: windows-jobs.yml@self 18 | parameters: 19 | # CI builds must pass true. 20 | isPublish: true 21 | # It must be false for real builds. Use true only for the build pipeline debugging. 22 | fakeBuild: false -------------------------------------------------------------------------------- /.ado/windows-pr.yml: -------------------------------------------------------------------------------- 1 | name: v8jsi_pr_0.0.$(Date:yyMM.d)$(Rev:rrr) 2 | 3 | trigger: none 4 | pr: 5 | - master 6 | - "*-stable" 7 | 8 | extends: 9 | template: windows-jobs.yml@self 10 | parameters: 11 | # PR builds must pass false. 12 | isPublish: false 13 | # It must be false for real builds. Use true only for the build pipeline debugging. 14 | fakeBuild: false 15 | -------------------------------------------------------------------------------- /.ado/windows-release.yml: -------------------------------------------------------------------------------- 1 | # 2 | # The v8-jsi Release pipeline entry point. 3 | # It releases NuGet packages to the public ms/react-native ADO feed and to the Office feed. 4 | # 5 | 6 | name: v8jsi_release_0.0.$(Date:yyMM.d)$(Rev:rrr) 7 | 8 | # The triggers are overridden by the ADO pipeline definitions. 9 | trigger: none 10 | pr: none 11 | 12 | resources: 13 | pipelines: 14 | - pipeline: microsoft.v8-jsi.ci 15 | project: ISS 16 | source: microsoft.v8-jsi.ci 17 | trigger: 18 | branches: 19 | include: 20 | - master 21 | - main 22 | - '*-stable' 23 | 24 | repositories: 25 | - repository: CustomPipelineTemplates 26 | type: git 27 | name: 1ESPipelineTemplates/OfficePipelineTemplates 28 | ref: refs/tags/release 29 | 30 | extends: 31 | template: v1/Office.Official.PipelineTemplate.yml@CustomPipelineTemplates 32 | parameters: 33 | pool: 34 | name: Azure-Pipelines-1ESPT-ExDShared 35 | vmImage: windows-latest 36 | os: windows 37 | 38 | stages: 39 | - stage: publish_nugets 40 | displayName: Publish V8Jsi NuGets 41 | 42 | jobs: 43 | - job: ms_react_native_nuget_job 44 | displayName: Publish Nuget to ms/react-native 45 | condition: succeeded() 46 | timeoutInMinutes: 0 47 | 48 | templateContext: 49 | inputs: 50 | - input: pipelineArtifact 51 | pipeline: microsoft.v8-jsi.ci 52 | artifactName: published-packages 53 | targetPath: $(Pipeline.Workspace)\published-packages 54 | 55 | steps: 56 | - script: dir /S $(Pipeline.Workspace)\published-packages 57 | displayName: Show directory contents 58 | 59 | - script: dotnet nuget list source 60 | displayName: Show Nuget sources 61 | 62 | # TODO: Fix the NuGet name after the service connection approval 63 | - task: 1ES.PublishNuGet@1 64 | displayName: NuGet push 65 | inputs: 66 | useDotNetTask: true 67 | packageParentPath: '$(Pipeline.Workspace)/published-packages' 68 | packagesToPush: '$(Pipeline.Workspace)/published-packages/ReactNative.V8Jsi.Windows.*.nupkg' 69 | nuGetFeedType: external 70 | publishFeedCredentials: 'Nuget - ms/react-native-public' 71 | externalEndpoint: 'Nuget - ms/react-native-public' 72 | publishPackageMetadata: true 73 | 74 | - job: office_nuget_job 75 | displayName: Publish Nuget to office 76 | condition: succeeded() 77 | timeoutInMinutes: 0 78 | 79 | templateContext: 80 | inputs: 81 | - input: pipelineArtifact 82 | pipeline: microsoft.v8-jsi.ci 83 | artifactName: published-packages 84 | targetPath: $(Pipeline.Workspace)\published-packages 85 | 86 | steps: 87 | - script: dir /S $(Pipeline.Workspace)\published-packages 88 | displayName: Show directory contents 89 | 90 | - script: dotnet nuget list source 91 | displayName: Show Nuget sources 92 | 93 | # TODO: Fix the NuGet name after the service connection approval 94 | - task: 1ES.PublishNuGet@1 95 | displayName: NuGet push 96 | inputs: 97 | useDotNetTask: true 98 | packageParentPath: '$(Pipeline.Workspace)/published-packages' 99 | packagesToPush: '$(Pipeline.Workspace)/published-packages/ReactNative.V8Jsi.Windows.*.nupkg' 100 | nuGetFeedType: external 101 | publishFeedCredentials: 'ES365-Office-Nuget-Package-Publisher' 102 | externalEndpoint: 'ES365-Office-Nuget-Package-Publisher' 103 | publishPackageMetadata: true 104 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -1 3 | AlignAfterOpenBracket: AlwaysBreak 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignEscapedNewlinesLeft: true 7 | AlignOperands: false 8 | AlignTrailingComments: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: Empty 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: true 17 | AlwaysBreakTemplateDeclarations: true 18 | BinPackArguments: false 19 | BinPackParameters: false 20 | BraceWrapping: 21 | AfterClass: false 22 | AfterControlStatement: false 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterObjCDeclaration: false 27 | AfterStruct: false 28 | AfterUnion: false 29 | BeforeCatch: false 30 | BeforeElse: false 31 | IndentBraces: false 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeBraces: Attach 34 | BreakBeforeTernaryOperators: true 35 | BreakConstructorInitializersBeforeComma: false 36 | BreakAfterJavaFieldAnnotations: false 37 | BreakStringLiterals: false 38 | ColumnLimit: 120 39 | CommentPragmas: '^ IWYU pragma:' 40 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 41 | ConstructorInitializerIndentWidth: 4 42 | ContinuationIndentWidth: 4 43 | Cpp11BracedListStyle: true 44 | DerivePointerAlignment: false 45 | DisableFormat: false 46 | ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ] 47 | IncludeBlocks: Preserve 48 | IncludeCategories: 49 | - Regex: 'pch.h' 50 | Priority: -1 51 | - Regex: '.*\.g\..*' 52 | Priority: 1 53 | - Regex: '^<.*\.h(pp)?>' 54 | Priority: 2 55 | - Regex: '^<.*' 56 | Priority: 3 57 | - Regex: '.*' 58 | Priority: 4 59 | IndentCaseLabels: true 60 | IndentWidth: 2 61 | IndentWrappedFunctionNames: false 62 | KeepEmptyLinesAtTheStartOfBlocks: false 63 | MacroBlockBegin: '' 64 | MacroBlockEnd: '' 65 | MaxEmptyLinesToKeep: 1 66 | NamespaceIndentation: None 67 | ObjCBlockIndentWidth: 2 68 | ObjCSpaceAfterProperty: true 69 | ObjCSpaceBeforeProtocolList: true 70 | PenaltyBreakBeforeFirstCallParameter: 1 71 | PenaltyBreakComment: 300 72 | PenaltyBreakFirstLessLess: 120 73 | PenaltyBreakString: 1000 74 | PenaltyExcessCharacter: 1000000 75 | PenaltyReturnTypeOnItsOwnLine: 200 76 | PointerAlignment: Right 77 | ReflowComments: true 78 | SortIncludes: true 79 | SpaceAfterCStyleCast: false 80 | SpaceBeforeAssignmentOperators: true 81 | SpaceBeforeParens: ControlStatements 82 | SpaceInEmptyParentheses: false 83 | SpacesBeforeTrailingComments: 1 84 | SpacesInAngles: false 85 | SpacesInContainerLiterals: true 86 | SpacesInCStyleCastParentheses: false 87 | SpacesInParentheses: false 88 | SpacesInSquareBrackets: false 89 | Standard: Cpp11 90 | TabWidth: 8 91 | UseTab: Never 92 | ... 93 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = false 5 | 6 | [*] 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | charset = utf-8 11 | end_of_line = lf 12 | indent_size = 2 13 | 14 | 15 | # Xml project files 16 | [*.{config,csproj,nuspec,props,targets,vcxitems,vcxproj,vcxproj.filters}] 17 | end_of_line = crlf 18 | insert_final_newline = false 19 | 20 | [*.ps1] 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | [package.json] 25 | insert_final_newline = false 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .vscode 3 | build.log 4 | src/version_gen.rc 5 | src/source_link_gen.json 6 | 7 | # outputs 8 | out 9 | *.nupkg 10 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global Catch-All 2 | * @microsoft/jshost 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | React Native V8 JSI adapter 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.jsi.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Facebook, Inc. and its affiliates. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.v8.md: -------------------------------------------------------------------------------- 1 | This license applies to all parts of V8 that are not externally 2 | maintained libraries. The externally maintained libraries used by V8 3 | are: 4 | 5 | - PCRE test suite, located in 6 | test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the 7 | test suite from PCRE-7.3, which is copyrighted by the University 8 | of Cambridge and Google, Inc. The copyright notice and license 9 | are embedded in regexp-pcre.js. 10 | 11 | - Layout tests, located in test/mjsunit/third_party/object-keys. These are 12 | based on layout tests from webkit.org which are copyrighted by 13 | Apple Computer, Inc. and released under a 3-clause BSD license. 14 | 15 | - Strongtalk assembler, the basis of the files assembler-arm-inl.h, 16 | assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, 17 | assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, 18 | assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, 19 | assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. 20 | This code is copyrighted by Sun Microsystems Inc. and released 21 | under a 3-clause BSD license. 22 | 23 | - Valgrind client API header, located at src/third_party/valgrind/valgrind.h 24 | This is released under the BSD license. 25 | 26 | - The Wasm C/C++ API headers, located at third_party/wasm-api/wasm.{h,hh} 27 | This is released under the Apache license. The API's upstream prototype 28 | implementation also formed the basis of V8's implementation in 29 | src/wasm/c-api.cc. 30 | 31 | These libraries have their own licenses; we recommend you read them, 32 | as their terms may differ from the terms below. 33 | 34 | Further license information can be found in LICENSE files located in 35 | sub-directories. 36 | 37 | Copyright 2014, the V8 project authors. All rights reserved. 38 | Redistribution and use in source and binary forms, with or without 39 | modification, are permitted provided that the following conditions are 40 | met: 41 | 42 | * Redistributions of source code must retain the above copyright 43 | notice, this list of conditions and the following disclaimer. 44 | * Redistributions in binary form must reproduce the above 45 | copyright notice, this list of conditions and the following 46 | disclaimer in the documentation and/or other materials provided 47 | with the distribution. 48 | * Neither the name of Google Inc. nor the names of its 49 | contributors may be used to endorse or promote products derived 50 | from this software without specific prior written permission. 51 | 52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /ReactNative.V8Jsi.Windows.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ReactNative.V8Jsi.Windows 5 | $Version$ 6 | 7 | Contains a Windows implementation of the V8 JSI wrapper for ReactNative ($VersionDetails$) 8 | Facebook, Google, Microsoft 9 | https://github.com/microsoft/v8-jsi 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ReactNative.V8Jsi.Windows.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(Platform) 4 | 5 | x86 6 | 7 | 8 | 9 | $(MSBuildThisFileDirectory)..\..\lib\win32\$(Configuration)\$(V8Platform);%(AdditionalLibraryDirectories) 10 | v8jsi.dll.lib;%(AdditionalDependencies) 11 | v8jsi.dll;%(DelayLoadDLLs) 12 | 13 | 14 | $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories) 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.79.1", 3 | "v8ref": "refs/branch-heads/12.1", 4 | "buildNumber": "285" 5 | } 6 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 6 | 7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 9 | provided by the bot. You will only need to do this once across all repos using our CLA. 10 | 11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /localbuild.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT license. 3 | param( 4 | [System.IO.DirectoryInfo]$SourcesPath = $PSScriptRoot, 5 | 6 | [System.IO.DirectoryInfo]$OutputPath = "$PSScriptRoot\out", 7 | 8 | [ValidateSet('x64', 'x86', 'arm64')] 9 | [String[]]$Platform = @('x64'), 10 | 11 | [ValidateSet('Debug', 'Release')] 12 | [String[]]$Configuration = @('Debug'), 13 | 14 | [ValidateSet('win32', 'android', 'linux', 'mac')] 15 | [String[]]$AppPlatform = @('win32'), 16 | 17 | [switch]$NoSetup, 18 | 19 | [switch]$FakeBuild 20 | ) 21 | 22 | if (!$NoSetup -and !$FakeBuild) { 23 | Write-Host "Downloading environment..." 24 | & ".\scripts\download_depottools.ps1" -SourcesPath $SourcesPath -NoADO 25 | 26 | if (!$?) { 27 | Write-Host "Failed to download depot-tools" 28 | exit 1 29 | } 30 | 31 | Write-Host "Fetching code..." 32 | & ".\scripts\fetch_code.ps1" -SourcesPath $SourcesPath -AppPlatform $AppPlatform[0] 33 | 34 | if (!$?) { 35 | Write-Host "Failed to retrieve the v8 code" 36 | exit 1 37 | } 38 | } else { 39 | & ".\scripts\download_depottools.ps1" -SourcesPath $SourcesPath -NoSetup -NoADO 40 | } 41 | 42 | foreach ($Plat in $Platform) { 43 | foreach ($Config in $Configuration) { 44 | foreach ($AppPlat in $AppPlatform) { 45 | Write-Host "Building $AppPlat $Plat $Config..." 46 | & ".\scripts\build.ps1" -SourcesPath $SourcesPath -OutputPath $OutputPath ` 47 | -Platform $Plat -Configuration $Config -AppPlatform $AppPlat -FakeBuild:$FakeBuild 48 | } 49 | } 50 | } 51 | 52 | if (!$?) { 53 | Write-Host "Build failure" 54 | Pop-Location 55 | exit 1 56 | } 57 | -------------------------------------------------------------------------------- /scripts/download_depottools.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT license. 3 | param( 4 | [System.IO.DirectoryInfo]$SourcesPath = $PSScriptRoot, 5 | [switch]$NoSetup, 6 | [switch]$NoADO 7 | ) 8 | 9 | $ASIO_VERSION = "1-22-1" 10 | 11 | $workpath = Join-Path $SourcesPath "build" 12 | 13 | if (!(Test-Path -Path $workpath)) { 14 | New-Item -ItemType "directory" -Path $workpath | Out-Null 15 | } 16 | 17 | if (! $NoSetup) { 18 | Write-Host "Downloading depot-tools.zip..." 19 | 20 | # This is the recommended way to get depot-tools on Windows, but the git checkout is much faster (shaves off about 5 minutes from CI loop runtime) 21 | $UseArchive = $false 22 | 23 | if ($UseArchive) { 24 | $output = [System.IO.Path]::GetTempFileName() 25 | Invoke-WebRequest -Uri "https://storage.googleapis.com/chrome-infra/depot_tools.zip" -OutFile "$output.zip" 26 | Write-Host "Unzipping depot-tools.zip..." 27 | Expand-Archive -path "$output.zip" -DestinationPath "$workpath\depot_tools" 28 | Remove-Item "$output.zip" 29 | } 30 | else { 31 | $env:GIT_REDIRECT_STDERR = '2>&1' 32 | Push-Location $workpath 33 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 34 | Pop-Location 35 | } 36 | 37 | # Download dependencies (ASIO used by Inspector implementation) 38 | $asioUrl ="https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-$ASIO_VERSION.zip" 39 | $asioDownload = Join-Path $workpath $(Split-Path -Path $asioUrl -Leaf) 40 | 41 | Invoke-WebRequest -Uri $asioUrl -OutFile $asioDownload 42 | $asioDownload | Expand-Archive -DestinationPath $workpath -Force 43 | } 44 | 45 | Write-Host "Modifying PATH..." 46 | 47 | $depot_tools_path = Join-Path $workpath "depot_tools" 48 | 49 | if (!$PSVersionTable.Platform -or $IsWindows) { 50 | $path = "$depot_tools_path;$Env:PATH" 51 | $path = ($path.Split(';') | Where-Object { $_ -notlike '*Chocolatey*' }) -join ';' 52 | } 53 | else { 54 | $path = "$depot_tools_path`:$Env:PATH" 55 | } 56 | 57 | $env:PATH = $path 58 | $env:DEPOT_TOOLS_WIN_TOOLCHAIN = 0 59 | $env:GCLIENT_PY3 = 1 60 | $env:ASIO_ROOT = Join-Path $workpath "asio-asio-$ASIO_VERSION\asio\include" 61 | 62 | if (! $NoADO) { 63 | Write-Host "##vso[task.setvariable variable=PATH;]$path" 64 | Write-Host "##vso[task.setvariable variable=DEPOT_TOOLS_WIN_TOOLCHAIN;]0" 65 | Write-Host "##vso[task.setvariable variable=GCLIENT_PY3;]1" 66 | Write-Host "##vso[task.setvariable variable=ASIO_ROOT;]$env:ASIO_ROOT" 67 | } -------------------------------------------------------------------------------- /scripts/patch/build.diff: -------------------------------------------------------------------------------- 1 | diff --git a/config/compiler/BUILD.gn b/config/compiler/BUILD.gn 2 | index de1cd6efc..ed87ccb75 100644 3 | --- a/config/compiler/BUILD.gn 4 | +++ b/config/compiler/BUILD.gn 5 | @@ -1758,7 +1758,7 @@ config("default_warnings") { 6 | # TODO(thakis): Remove this once 7 | # https://swiftshader-review.googlesource.com/c/SwiftShader/+/57968 has 8 | # rolled into angle. 9 | - cflags += [ "/wd4244" ] 10 | + # cflags += [ "/wd4244" ] 11 | } 12 | } else { 13 | if (is_apple && !is_nacl) { 14 | @@ -2045,7 +2045,7 @@ config("no_chromium_code") { 15 | } 16 | cflags += [ 17 | "/wd4800", # Disable warning when forcing value to bool. 18 | - "/wd4267", # TODO(jschuh): size_t to int. 19 | + # "/wd4267", # TODO(jschuh): size_t to int. 20 | ] 21 | } else { 22 | if (is_clang && !is_nacl) { 23 | diff --git a/config/win/BUILD.gn b/config/win/BUILD.gn 24 | index 6e1417aa4..4079a06c8 100644 25 | --- a/config/win/BUILD.gn 26 | +++ b/config/win/BUILD.gn 27 | @@ -486,16 +486,16 @@ config("default_crt") { 28 | # Component mode: dynamic CRT. Since the library is shared, it requires 29 | # exceptions or will give errors about things not matching, so keep 30 | # exceptions on. 31 | - configs = [ ":dynamic_crt" ] 32 | + configs = [ ":dynamic_crt", ":win_msvc_cfg" ] 33 | } else { 34 | if (current_os == "winuwp") { 35 | # https://blogs.msdn.microsoft.com/vcblog/2014/06/10/the-great-c-runtime-crt-refactoring/ 36 | # contains a details explanation of what is happening with the Windows 37 | # CRT in Visual Studio releases related to Windows store applications. 38 | - configs = [ ":dynamic_crt" ] 39 | + configs = [ ":dynamic_crt", ":win_msvc_cfg" ] 40 | } else { 41 | # Desktop Windows: static CRT. 42 | - configs = [ ":static_crt" ] 43 | + configs = [ ":dynamic_crt", ":win_msvc_cfg" ] 44 | } 45 | } 46 | } 47 | @@ -689,3 +689,11 @@ config("lean_and_mean") { 48 | config("nominmax") { 49 | defines = [ "NOMINMAX" ] 50 | } 51 | + 52 | +# Control Flow Guard (CFG) 53 | +config("win_msvc_cfg") { 54 | + if (!is_clang) { 55 | + cflags = [ "/guard:cf", "/Qspectre", "/W3" ] 56 | + ldflags = [ "/guard:cf" ] 57 | + } 58 | +} 59 | \ No newline at end of file 60 | diff --git a/toolchain/win/setup_toolchain.py b/toolchain/win/setup_toolchain.py 61 | index 521c24398..3677b5a2f 100644 62 | --- a/toolchain/win/setup_toolchain.py 63 | +++ b/toolchain/win/setup_toolchain.py 64 | @@ -186,6 +186,8 @@ def _LoadToolchainEnv(cpu, toolchain_root, sdk_dir, target_store): 65 | # building with a new and untested SDK. This should stay in sync with the 66 | # packaged toolchain in build/vs_toolchain.py. 67 | args.append(SDK_VERSION) 68 | + # Use Spectre runtime libraries 69 | + args.append('-vcvars_spectre_libs=spectre') 70 | variables = _LoadEnvFromBat(args) 71 | return _ExtractImportantEnvironment(variables) 72 | 73 | -------------------------------------------------------------------------------- /scripts/patch/zlib.diff: -------------------------------------------------------------------------------- 1 | diff --git a/BUILD.gn b/BUILD.gn 2 | index 49f52e1..7ee4871 100644 3 | --- a/BUILD.gn 4 | +++ b/BUILD.gn 5 | @@ -32,7 +32,7 @@ config("zlib_internal_config") { 6 | # V8 supports building with msvc, these silence some warnings that 7 | # causes compilation to fail (https://crbug.com/1255096). 8 | cflags = [ 9 | - "/wd4244", 10 | + #"/wd4244", 11 | "/wd4100", 12 | "/wd4702", 13 | "/wd4127", 14 | -------------------------------------------------------------------------------- /scripts/update_version.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT license. 3 | param( 4 | [System.IO.DirectoryInfo]$SourcesPath = $PSScriptRoot, 5 | [switch]$BetaBranch, 6 | [switch]$GitPush 7 | ) 8 | 9 | # Details about the V8 release process: https://v8.dev/docs/release-process 10 | 11 | # TODO: a cron ADO task should trigger this script to update the version 12 | 13 | # https://omahaproxy.appspot.com is deprecated in favor of https://chromiumdash.appspot.com 14 | 15 | $channel = "Stable" 16 | if ($BetaBranch) { 17 | $channel = "Beta" 18 | } 19 | 20 | $latestVersion = (Invoke-WebRequest "https://chromiumdash.appspot.com/fetch_releases?channel=$channel&platform=Windows&num=1" -UseBasicParsing | ConvertFrom-Json).milestone / 10 21 | 22 | Write-Host "Latest $channel version is $latestVersion" 23 | 24 | $config = Get-Content (Join-Path $SourcesPath "config.json") | Out-String | ConvertFrom-Json 25 | $builtVersion = (($config.v8ref | Select-String -Pattern "refs/branch-heads/(\d+\.\d+)").Matches[0].Groups[1].Value).Trim() 26 | 27 | Write-Host "Version currently being built is $builtVersion" 28 | 29 | if ($builtVersion -eq $latestVersion) { 30 | Write-Host "Latest $channel version is already being built" 31 | } else { 32 | Write-Host "New $channel version released, manual intervention required to bump the version!" 33 | exit 1 34 | } 35 | 36 | function GetLatestBuildNumberForVersion($buildingVersion) { 37 | $versionUrl = "https://chromium.googlesource.com/v8/v8.git/+/refs/heads/$buildingVersion-lkgr/include/v8-version.h?format=text" 38 | $content = Invoke-WebRequest -ContentType 'text/plain' -Uri $versionUrl -UseBasicParsing 39 | $content = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($content.Content)) 40 | $majorVersion = (($content | Select-String -Pattern "V8_MAJOR_VERSION (\d+)").Matches[0].Groups[1].Value).Trim() 41 | $minorVersion = (($content | Select-String -Pattern "V8_MINOR_VERSION (\d+)").Matches[0].Groups[1].Value).Trim() 42 | $buildNumber = (($content | Select-String -Pattern "V8_BUILD_NUMBER (\d+)").Matches[0].Groups[1].Value).Trim() 43 | $patchLevel = (($content | Select-String -Pattern "V8_PATCH_LEVEL (\d+)").Matches[0].Groups[1].Value).Trim() 44 | 45 | # TODO: do this for every new $patchLevel as well? 46 | return $buildNumber 47 | } 48 | 49 | function BumpSemVer($version) { 50 | $versionParts = $version.Split('.') 51 | $versionParts[2] = [int]$versionParts[2] + 1 52 | return $versionParts -join '.' 53 | } 54 | 55 | $buildNumber = GetLatestBuildNumberForVersion($latestVersion) 56 | 57 | Write-Host "Latest build number upstream is $buildNumber" 58 | Write-Host "Build number currently being built is $($config.buildNumber)" 59 | 60 | if ($buildNumber -eq $config.buildNumber) { 61 | Write-Host "Latest build number is already being built. All good!" 62 | exit 0 63 | } 64 | 65 | Write-Host "New $channel build number released, attempting to bump it" 66 | 67 | $config.buildNumber = $buildNumber 68 | $config.version = BumpSemVer($config.version) 69 | 70 | ConvertTo-Json -InputObject $config | Set-Content (Join-Path $SourcesPath "config.json") 71 | 72 | if (! $GitPush) { 73 | Write-Host "Git push not requested, we would be updating the version to $($config.version) (new upstream build number $buildNumber)" 74 | } else { 75 | git config user.name github-actions 76 | git config user.email github-actions@github.com 77 | git add config.json 78 | git commit -m "Updating version to $($config.version) (new upstream build number $buildNumber)" 79 | git push 80 | } -------------------------------------------------------------------------------- /src/IsolateData.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #pragma once 4 | 5 | #include "v8.h" 6 | 7 | #include "public/V8JsiRuntime.h" 8 | 9 | namespace v8runtime { 10 | 11 | constexpr int ISOLATE_DATA_SLOT = 0; 12 | constexpr int ISOLATE_INSPECTOR_SLOT = 1; 13 | 14 | // Custom data associated with each V8 isolate. 15 | struct IsolateData { 16 | IsolateData(v8::Isolate *isolate, std::shared_ptr foreground_task_runner) noexcept 17 | : isolate_{isolate}, foreground_task_runner_{std::move(foreground_task_runner)} {} 18 | 19 | std::shared_ptr foreground_task_runner_; 20 | 21 | v8::Local napi_type_tag() const { 22 | return napi_type_tag_.Get(isolate_); 23 | } 24 | 25 | v8::Local napi_wrapper() const { 26 | return napi_wrapper_.Get(isolate_); 27 | } 28 | 29 | v8::Local nativeStateKey() const { 30 | return nativeStateKey_.Get(isolate_); 31 | } 32 | 33 | // Creates property names often used by the NAPI implementation. 34 | void CreateProperties() { 35 | v8::HandleScope handle_scope(isolate_); 36 | CreateProperty(napi_type_tag_, "node:napi:type_tag"); 37 | CreateProperty(napi_wrapper_, "node:napi:wrapper"); 38 | CreateProperty(nativeStateKey_, "v8:jsi:nativeStateKey"); 39 | } 40 | 41 | private: 42 | template 43 | void CreateProperty(v8::Eternal &property, const char (&name)[N]) { 44 | property.Set( 45 | isolate_, 46 | v8::Private::New( 47 | isolate_, 48 | v8::String::NewFromOneByte( 49 | isolate_, reinterpret_cast(name), v8::NewStringType::kInternalized, N - 1) 50 | .ToLocalChecked())); 51 | } 52 | 53 | private: 54 | v8::Isolate *isolate_; 55 | v8::Eternal napi_type_tag_; 56 | v8::Eternal napi_wrapper_; 57 | v8::Eternal nativeStateKey_; 58 | }; 59 | 60 | } // namespace v8runtime 61 | -------------------------------------------------------------------------------- /src/MurmurHash.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | // Computes the hash of key using MurmurHash3 algorithm, the value is planced in the "hash" output parameter 9 | // The function returns whether or not key is comprised of only ASCII characters (<=127) 10 | bool murmurhash(const uint8_t *key, size_t length, uint64_t &hash); -------------------------------------------------------------------------------- /src/V8Instrumentation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace v8runtime { 7 | 8 | class V8Instrumentation : public facebook::jsi::Instrumentation { 9 | public: 10 | explicit V8Instrumentation(v8::Isolate *isolate); 11 | 12 | std::string getRecordedGCStats() override; 13 | std::unordered_map getHeapInfo(bool includeExpensive) override; 14 | void collectGarbage(std::string cause) override; 15 | void startTrackingHeapObjectStackTraces( 16 | std::function< 17 | void(uint64_t lastSeenObjectID, std::chrono::microseconds timestamp, std::vector stats)> 18 | fragmentCallback) override; 19 | void stopTrackingHeapObjectStackTraces() override; 20 | void startHeapSampling(size_t samplingInterval) override; 21 | void stopHeapSampling(std::ostream &os) override; 22 | #if JSI_VERSION >= 13 23 | void createSnapshotToFile(const std::string &path, const HeapSnapshotOptions &options = {false}) override; 24 | void createSnapshotToStream(std::ostream &os, const HeapSnapshotOptions &options = {false}) override; 25 | #else 26 | void createSnapshotToFile(const std::string &path) override; 27 | void createSnapshotToStream(std::ostream &os) override; 28 | #endif 29 | std::string flushAndDisableBridgeTrafficTrace() override; 30 | void writeBasicBlockProfileTraceToFile(const std::string &fileName) const override; 31 | void dumpProfilerSymbolsToFile(const std::string &fileName) const override; 32 | 33 | private: 34 | void createSnapshotToStreamImpl(std::ostream &os, bool captureNumericValue = false); 35 | 36 | private: 37 | v8::Isolate *isolate_; 38 | }; 39 | 40 | } // namespace v8runtime 41 | -------------------------------------------------------------------------------- /src/V8Windows.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #pragma once 4 | 5 | #ifndef SRC_V8WINDOWS_H 6 | #define SRC_V8WINDOWS_H 7 | 8 | #ifdef _WIN32 9 | 10 | #ifndef NOMINMAX 11 | #define NOMINMAX 12 | #endif // NOMINMAX 13 | 14 | #ifndef WIN32_LEAN_AND_MEAN 15 | #define WIN32_LEAN_AND_MEAN 16 | #endif // WIN32_LEAN_AND_MEAN 17 | 18 | #include 19 | 20 | #endif 21 | 22 | #include "etw/tracing.h" 23 | 24 | #endif // SRC_V8WINDOWS_H 25 | -------------------------------------------------------------------------------- /src/etw/tracing.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #include "V8Windows.h" 4 | #include "tracing.h" 5 | 6 | // Define the GUID to use in TraceLoggingProviderRegister 7 | // {85A99459-1F1D-49BD-B3DC-E5EF2AD0C2C8} 8 | TRACELOGGING_DEFINE_PROVIDER( 9 | g_hV8JSIRuntimeTraceLoggingProvider, 10 | "Microsoft.V8JSIRuntime", 11 | (0x85a99459, 0x1f1d, 0x49bd, 0xb3, 0xdc, 0xe5, 0xef, 0x2a, 0xd0, 0xc2, 0xc8)); 12 | 13 | // Define the GUID to use in TraceLoggingProviderRegister 14 | // {5509957C-25B6-4294-B2FA-8A8E41E6BC37} 15 | TRACELOGGING_DEFINE_PROVIDER( 16 | g_hV8JSIInspectorTraceLoggingProvider, 17 | "Microsoft.V8JSIInspector", 18 | (0x5509957c, 0x25b6, 0x4294, 0xb2, 0xfa, 0x8a, 0x8e, 0x41, 0xe6, 0xbc, 0x37)); 19 | 20 | void globalInitializeTracing() { 21 | #ifdef _WIN32 22 | TraceLoggingUnregister(g_hV8JSIRuntimeTraceLoggingProvider); 23 | TraceLoggingRegister(g_hV8JSIRuntimeTraceLoggingProvider); 24 | TraceLoggingUnregister(g_hV8JSIInspectorTraceLoggingProvider); 25 | TraceLoggingRegister(g_hV8JSIInspectorTraceLoggingProvider); 26 | #endif 27 | 28 | TRACEV8RUNTIME_VERBOSE("Initializing providers."); 29 | } 30 | -------------------------------------------------------------------------------- /src/etw/tracing.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #pragma once 4 | 5 | #ifdef _WIN32 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | TRACELOGGING_DECLARE_PROVIDER(g_hV8JSIRuntimeTraceLoggingProvider); 14 | TRACELOGGING_DECLARE_PROVIDER(g_hV8JSIInspectorTraceLoggingProvider); 15 | 16 | // Ref: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/tracelogging-examples 17 | #define TRACEV8RUNTIME_VERBOSE(eventName, ...) \ 18 | TraceLoggingWrite( \ 19 | g_hV8JSIRuntimeTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_VERBOSE), __VA_ARGS__); 20 | 21 | #define TRACEV8RUNTIME_WARNING(eventName, ...) \ 22 | TraceLoggingWrite( \ 23 | g_hV8JSIRuntimeTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_WARNING), __VA_ARGS__); 24 | 25 | #define TRACEV8RUNTIME_ERROR(eventName, ...) \ 26 | TraceLoggingWrite(g_hV8JSIRuntimeTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_ERROR), __VA_ARGS__); 27 | 28 | #define TRACEV8RUNTIME_CRITICAL(eventName, ...) \ 29 | TraceLoggingWrite( \ 30 | g_hV8JSIRuntimeTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_CRITICAL), __VA_ARGS__); 31 | 32 | // Ref: 33 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/tracelogging-examples 34 | #define TRACEV8INSPECTOR_VERBOSE(eventName, ...) \ 35 | TraceLoggingWrite( \ 36 | g_hV8JSIInspectorTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_VERBOSE), __VA_ARGS__); 37 | 38 | #define TRACEV8INSPECTOR_WARNING(eventName, ...) \ 39 | TraceLoggingWrite( \ 40 | g_hV8JSIInspectorTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_WARNING), __VA_ARGS__); 41 | 42 | #define TRACEV8INSPECTOR_ERROR(eventName, ...) \ 43 | TraceLoggingWrite( \ 44 | g_hV8JSIInspectorTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_ERROR), __VA_ARGS__); 45 | 46 | #define TRACEV8INSPECTOR_CRITICAL(eventName, ...) \ 47 | TraceLoggingWrite( \ 48 | g_hV8JSIInspectorTraceLoggingProvider, eventName, TraceLoggingLevel(TRACE_LEVEL_CRITICAL), __VA_ARGS__); 49 | 50 | void globalInitializeTracing(); 51 | 52 | #ifdef __cplusplus 53 | } // extern "C" 54 | #endif 55 | 56 | #else // WIN32 57 | 58 | #define TRACEV8RUNTIME_VERBOSE(eventName, ...) 59 | #define TRACEV8RUNTIME_WARNING(eventName, ...) 60 | #define TRACEV8RUNTIME_CRITICAL(eventName, ...) 61 | #define TraceLoggingString(foo,bar) 62 | 63 | #endif -------------------------------------------------------------------------------- /src/inspector/LICENSE_LLHTTP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/v8-jsi/ac52b54efec5bf164c9d8766f7411ca394a2d6a8/src/inspector/LICENSE_LLHTTP -------------------------------------------------------------------------------- /src/inspector/LICENSE_NODE: -------------------------------------------------------------------------------- 1 | Copyright Node.js contributors. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/inspector/inspector_agent.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | // This code is based on the old node inspector implementation. See LICENSE_NODE for Node.js' project license details 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace inspector { 12 | 13 | class AgentImpl; 14 | 15 | class Agent : public std::enable_shared_from_this { 16 | public: 17 | explicit Agent( 18 | v8::Isolate *isolate, 19 | int port); 20 | ~Agent(); 21 | 22 | void waitForDebugger(); 23 | 24 | void addContext(v8::Local context, const char* context_name); 25 | void removeContext(v8::Local context); 26 | 27 | void start(); 28 | void stop(); 29 | 30 | bool IsStarted(); 31 | bool IsConnected(); 32 | void WaitForDisconnect(); 33 | void FatalException( 34 | v8::Local error, 35 | v8::Local message); 36 | 37 | void notifyLoadedUrl(const std::string& url); 38 | std::shared_ptr getShared(); 39 | 40 | static void startAll(); 41 | 42 | private: 43 | std::shared_ptr impl; 44 | static std::unordered_set> agents_s_; 45 | }; 46 | 47 | } // namespace inspector 48 | -------------------------------------------------------------------------------- /src/inspector/inspector_socket.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | // This code is based on the old node inspector implementation. See LICENSE_NODE for Node.js' project license details 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "inspector_tcp.h" 11 | 12 | namespace inspector { 13 | 14 | class ProtocolHandler; 15 | 16 | class InspectorSocket { 17 | public: 18 | InspectorSocket() = default; 19 | ~InspectorSocket(); 20 | 21 | class Delegate { 22 | public: 23 | virtual void OnHttpGet(const std::string& host, 24 | const std::string& path) = 0; 25 | virtual void OnSocketUpgrade(const std::string& host, 26 | const std::string& path, 27 | const std::string& accept_key) = 0; 28 | virtual void OnWsFrame(const std::vector& frame) = 0; 29 | virtual ~Delegate() {} 30 | }; 31 | 32 | static std::unique_ptr Accept(std::shared_ptr connection, std::unique_ptr&& delegate); 33 | 34 | void AcceptUpgrade(const std::string& accept_key); 35 | void CancelHandshake(); 36 | void Write(const char* data, size_t len); 37 | void SwitchProtocol(std::unique_ptr&& handler); 38 | std::string GetHost(); 39 | 40 | private: 41 | std::unique_ptr protocol_handler_; 42 | 43 | InspectorSocket(const InspectorSocket&) = delete; 44 | InspectorSocket& operator=(const InspectorSocket&) = delete; 45 | }; 46 | 47 | } // namespace inspector 48 | -------------------------------------------------------------------------------- /src/inspector/inspector_socket_server.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | // This code is based on the old node inspector implementation. See LICENSE_NODE for Node.js' project license details 4 | #pragma once 5 | 6 | #include "inspector_agent.h" 7 | #include "inspector_socket.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace inspector { 15 | 16 | class InspectorSocketServer; 17 | class SocketSession; 18 | class ServerSocket; 19 | 20 | class InspectorAgentDelegate { 21 | public: 22 | InspectorAgentDelegate(); 23 | void StartSession(int session_id, const std::string &target_id); 24 | void MessageReceived(int session_id, const std::string &message); 25 | void EndSession(int session_id); 26 | std::vector GetTargetIds(); 27 | std::string GetTargetTitle(const std::string &id); 28 | std::string GetTargetUrl(const std::string &id); 29 | void AddTarget(std::shared_ptr agent); 30 | void RemoveTarget(std::shared_ptr agent); 31 | bool HasTargets(); 32 | 33 | private: 34 | std::unordered_map> targets_map_; 35 | std::unordered_map> session_targets_map_; 36 | }; 37 | 38 | // HTTP Server, writes messages requested as TransportActions, and responds 39 | // to HTTP requests and WS upgrades. 40 | 41 | class InspectorSocketServer : public std::enable_shared_from_this { 42 | public: 43 | InspectorSocketServer(std::unique_ptr&& delegate, int port, 44 | FILE* out = stderr); 45 | ~InspectorSocketServer(); 46 | 47 | // Start listening on host/port 48 | bool Start(); 49 | 50 | void Stop(); 51 | void Send(int session_id, const std::string& message); 52 | void TerminateConnections(); 53 | int Port() const; 54 | 55 | void AddTarget(std::shared_ptr agent); 56 | void RemoveTarget(std::shared_ptr agent); 57 | bool HasTargets(); 58 | 59 | // Session connection lifecycle 60 | void Accept(std::shared_ptr connection, int server_port/*, uv_stream_t* server_socket*/); 61 | bool HandleGetRequest(int session_id, const std::string& host, const std::string& path); 62 | void SessionStarted(int session_id, const std::string& target_id, const std::string& ws_id); 63 | void SessionTerminated(int session_id); 64 | void MessageReceived(int session_id, const std::string& message) { 65 | delegate_->MessageReceived(session_id, message); 66 | } 67 | SocketSession* Session(int session_id); 68 | 69 | static void SocketConnectedCallback(std::shared_ptr connection, void* callbackData_); 70 | static void SocketClosedCallback(void* callbackData_); 71 | 72 | private: 73 | static void CloseServerSocket(ServerSocket*); 74 | 75 | void SendListResponse(InspectorSocket* socket, const std::string& host, SocketSession* session); 76 | std::string GetFrontendURL(bool is_compat, const std::string &formatted_address); 77 | bool TargetExists(const std::string& id); 78 | 79 | enum class ServerState { kNew, kRunning, kStopping, kStopped }; 80 | std::unique_ptr delegate_; 81 | const std::string host_; 82 | int port_; 83 | 84 | std::mutex mutex_tcp_server_; 85 | std::shared_ptr tcp_server_; 86 | bool tcp_server_stopped_{false}; 87 | 88 | int next_session_id_; 89 | FILE* out_; 90 | ServerState state_; 91 | 92 | std::map>> connected_sessions_; 93 | 94 | }; 95 | 96 | } // namespace inspector 97 | -------------------------------------------------------------------------------- /src/inspector/inspector_tcp.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | // This code is based on the old node inspector implementation. See LICENSE_NODE for Node.js' project license details 4 | #pragma once 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace inspector { 12 | 13 | class tcp_connection : public std::enable_shared_from_this 14 | { 15 | public: 16 | asio::ip::tcp::socket& socket(); 17 | 18 | typedef void(*ReadCallback)(std::vector&, bool iseof, void*data); 19 | inline void registerReadCallback(ReadCallback callback, void*data) { readcallback_ = callback; callbackData_ = data; } 20 | 21 | void read_loop_async(); 22 | void write_async(std::vector&&); 23 | void close(); 24 | 25 | inline tcp_connection(asio::ip::tcp::socket socket) 26 | : socket_(std::move(socket)) {} 27 | private: 28 | void do_write(bool cont); 29 | 30 | private: 31 | int port_; 32 | 33 | asio::ip::tcp::socket socket_; 34 | std::string message_; 35 | 36 | /// Buffer for incoming data. 37 | std::array buffer_; 38 | 39 | void* callbackData_; 40 | ReadCallback readcallback_; 41 | 42 | std::mutex queueAccessMutex; 43 | std::queue> outQueue; 44 | 45 | std::vector messageToWrite_; 46 | bool writing_{ false }; 47 | }; 48 | 49 | class tcp_server : public std::enable_shared_from_this { 50 | public: 51 | typedef void(*ConnectionCallback)(std::shared_ptr connection, void* callbackData_); 52 | 53 | void run(); 54 | void stop(); 55 | 56 | tcp_server(int port, ConnectionCallback callback, void* data); 57 | 58 | private: 59 | void do_accept(); 60 | 61 | private: 62 | asio::io_service io_service_; 63 | asio::ip::tcp::acceptor acceptor_; 64 | asio::ip::tcp::socket socket_; 65 | 66 | void* callbackData_; 67 | ConnectionCallback connectioncallback_; 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/jsi/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: InheritParentConfig 3 | PointerAlignment: Left 4 | ColumnLimit: 80 5 | ... 6 | -------------------------------------------------------------------------------- /src/jsi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) Meta Platforms, Inc. and affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | set(CMAKE_CXX_STANDARD 14) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | add_library(jsi 10 | jsi.cpp) 11 | 12 | target_include_directories(jsi PUBLIC ..) 13 | 14 | 15 | set(jsi_compile_flags "") 16 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR 17 | "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 18 | list(APPEND jsi_compile_flags "-Wno-non-virtual-dtor") 19 | elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") 20 | # Turn on Error Handling in MSVC, otherwise objects are not destructed 21 | # when they go out of scope due to exceptions. 22 | list(APPEND jsi_compile_flags "/EHsc") 23 | list(APPEND jsi_compile_flags "/Zi") 24 | list(APPEND jsi_compile_flags "/Qspectre") 25 | list(APPEND jsi_compile_flags "/sdl") 26 | endif() 27 | 28 | target_compile_options(jsi PRIVATE ${jsi_compile_flags}) 29 | 30 | install(DIRECTORY "${PROJECT_SOURCE_DIR}/API/jsi/" DESTINATION include 31 | FILES_MATCHING PATTERN "*.h" 32 | PATTERN "test" EXCLUDE) 33 | -------------------------------------------------------------------------------- /src/jsi/JSIDynamic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | namespace facebook { 14 | namespace jsi { 15 | 16 | facebook::jsi::Value valueFromDynamic( 17 | facebook::jsi::Runtime& runtime, 18 | const folly::dynamic& dyn); 19 | 20 | folly::dynamic dynamicFromValue( 21 | facebook::jsi::Runtime& runtime, 22 | const facebook::jsi::Value& value, 23 | const std::function& filterObjectKeys = nullptr); 24 | 25 | } // namespace jsi 26 | } // namespace facebook 27 | -------------------------------------------------------------------------------- /src/jsi/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Interface 2 | 3 | This folder contains definitions for JSI. 4 | JSI is the public API for Hermes engine. 5 | It is being used by React Native project to work with JS engines. 6 | 7 | ## JSI versions 8 | 9 | JSI has versions associated with the following commit hashes in the 10 | https://github.com/facebook/hermes repo. 11 | 12 | | Version | Commit Hash | Commit Description 13 | |--------:|:-------------------------------------------|------------------------------------------------------ 14 | | 19 | `00a84e7bae9b8569e7b3f4118f4238544c67fe1b` | Add createFromUtf16 JSI method 15 | | 18 | `d0328097291aade7269b2879910e11c48c8fbeb1` | Add default implementation for Object.create(prototype) 16 | | 17 | `1012f891165e7dda3b51939b75bbc52e16e48a75` | Add default implementation for Object.getPrototypeOf and Object.setPrototypeOf 17 | | 16 | `215bbe6ddc75393332b74138205e7cf5ab874e4e` | Add default getStringData/getPropNameIdData implementation 18 | | 15 | `54e428c749358fb4aa25c6d7e2dcc3fc23b47124` | Let Pointer be nothrow-move-constructible 19 | | | `c582a23d62505a00948f5aa49006f60f959f8df4` | Let PointerValue::invalidate() be noexcept 20 | | | `b07ef4fc10dd53ad542f811040c820064c5ceb57` | Let Value be nothrow-move-constructible 21 | | 14 | `c98b00e88bb685e75b769be67919a23a7f03b2e0` | Add utf16 method to JSI 22 | | 13 | `077f2633dea36e1d0d18d6c4f114bf66e3ab74cf` | Add HeapSnapshotOptions for jsi::Instrumentation 23 | | 12 | `de9dfe408bc3f8715aef161c5fcec291fc6dacb2` | Add queueMicrotask method to JSI 24 | | | `a699e87f995bc2f7193990ff36a57ec9cad940e5` | Make queueMicrotask pure virtual 25 | | 11 | `a1c168705f609c8f1ae800c60d88eb199154264b` | Add JSI method for setting external memory size 26 | | 10 | `b81666598672cb5f8b365fe6548d3273f216322e` | Clarify const-ness of JSI references 27 | | 9 | `e6d887ae96bef5c71032f11ed1a9fb9fecec7b46` | Add external ArrayBuffers to JSI 28 | | 8 | `4d64e61a1f9926eca0afd4eb38d17cea30bdc34c` | Add BigInt JSI API support 29 | | | `e8cc57311877464478da5421265bcc898098e136` | Add methods for creating and interacting with BigInt 30 | | 7 | `4efad65b8266e3f26e04e3ca9addf92fc4d6ded8` | Add API for setting/getting native state 31 | | 6 | `bc3cfb87fbfc82732936ec4445c9765bf9a5f08a` | Add BigInt skeleton 32 | | 5 | `2b6d408980d7f23f50602fd88169c8a9881592a6` | Add PropNameID::fromSymbol 33 | | 4 | `a5bee55c8301bb8662e408feee28bbc3e2a1fc81` | Introduce drainMicrotasks to JSI 34 | | 3 | `0c9daa5a5eee7649558a53e3e541b80c89048c42` | Change jsi::Runtime::lockWeakObject to take a mutable ref 35 | | 2 | `e0616e77e1ddc3ea5e2ccbca2e20dd0c4049c637` | Make it possible for a Runtime implementation to provide its own JSON parsing 36 | | 1 | `3ba9615f80913764ecb6456779d502e31dde9e5d` | Fix build break in MSVC (#26462) 37 | | 0 | `f22a18f67da3f03db59c1ec715d6ec3776b03fbf` | Initial commit 38 | 39 | Relationship to React Native versions: 40 | 41 | | RN Version | JSI version | 42 | |-----------:|------------:| 43 | | main | 12 | 44 | | 0.74 | 11 | 45 | | 0.73 | 10 | 46 | | 0.72 | 10 | 47 | | 0.71 | 9 | 48 | | 0.70 | 6 | 49 | | 0.69 | 5 | 50 | -------------------------------------------------------------------------------- /src/jsi/jsilib-posix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef _WINDOWS 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | namespace facebook { 22 | namespace jsi { 23 | 24 | namespace { 25 | 26 | constexpr size_t kErrorBufferSize = 512; 27 | 28 | __attribute__((format(printf, 1, 2))) void throwFormattedError( 29 | const char* fmt, 30 | ...) { 31 | char logBuffer[kErrorBufferSize]; 32 | 33 | va_list va_args; 34 | va_start(va_args, fmt); 35 | int result = vsnprintf(logBuffer, sizeof(logBuffer), fmt, va_args); 36 | va_end(va_args); 37 | 38 | if (result < 0) { 39 | throw JSINativeException( 40 | std::string("Failed to format error message: ") + fmt); 41 | } 42 | 43 | throw JSINativeException(logBuffer); 44 | } 45 | 46 | class ScopedFile { 47 | public: 48 | ScopedFile(const std::string& path) 49 | : path_(path), fd_(::open(path.c_str(), O_RDONLY)) { 50 | if (fd_ == -1) { 51 | throwFormattedError( 52 | "Could not open %s: %s", path.c_str(), strerror(errno)); 53 | } 54 | } 55 | 56 | ~ScopedFile() { 57 | ::close(fd_); 58 | } 59 | 60 | size_t size() { 61 | struct stat fileInfo; 62 | if (::fstat(fd_, &fileInfo) == -1) { 63 | throwFormattedError( 64 | "Could not stat %s: %s", path_.c_str(), strerror(errno)); 65 | } 66 | return fileInfo.st_size; 67 | } 68 | 69 | uint8_t* mmap(size_t size) { 70 | void* result = ::mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd_, 0); 71 | if (result == MAP_FAILED) { 72 | throwFormattedError( 73 | "Could not mmap %s: %s", path_.c_str(), strerror(errno)); 74 | } 75 | return reinterpret_cast(result); 76 | } 77 | 78 | const std::string& path_; 79 | const int fd_; 80 | }; 81 | 82 | } // namespace 83 | 84 | FileBuffer::FileBuffer(const std::string& path) { 85 | ScopedFile file(path); 86 | size_ = file.size(); 87 | data_ = file.mmap(size_); 88 | } 89 | 90 | FileBuffer::~FileBuffer() { 91 | if (::munmap(data_, size_)) { 92 | // terminate the program with pending exception 93 | try { 94 | throwFormattedError( 95 | "Could not unmap memory (%p, %zu bytes): %s", 96 | data_, 97 | size_, 98 | strerror(errno)); 99 | } catch (...) { 100 | std::terminate(); 101 | } 102 | } 103 | } 104 | 105 | } // namespace jsi 106 | } // namespace facebook 107 | 108 | #endif // !defined(_WINDOWS) 109 | -------------------------------------------------------------------------------- /src/jsi/jsilib-windows.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifdef _WINDOWS 9 | 10 | #include 11 | 12 | namespace facebook { 13 | namespace jsi { 14 | 15 | FileBuffer::FileBuffer(const std::string&) { 16 | // TODO(T41045067) Implement this on Windows 17 | throw new JSINativeException("FileBuffer is not implemented on Windows"); 18 | } 19 | 20 | FileBuffer::~FileBuffer() { 21 | assert(false && "FileBuffer is not implemented on Windows"); 22 | } 23 | 24 | } // namespace jsi 25 | } // namespace facebook 26 | 27 | #endif //_WINDOWS 28 | -------------------------------------------------------------------------------- /src/jsi/jsilib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace facebook { 13 | namespace jsi { 14 | 15 | class FileBuffer : public Buffer { 16 | public: 17 | FileBuffer(const std::string& path); 18 | ~FileBuffer() override; 19 | 20 | size_t size() const override { 21 | return size_; 22 | } 23 | 24 | const uint8_t* data() const override { 25 | return data_; 26 | } 27 | 28 | private: 29 | size_t size_; 30 | uint8_t* data_; 31 | }; 32 | 33 | // A trivial implementation of PreparedJavaScript that simply stores the source 34 | // buffer and URL. 35 | class SourceJavaScriptPreparation final : public jsi::PreparedJavaScript, 36 | public jsi::Buffer { 37 | std::shared_ptr buf_; 38 | std::string sourceURL_; 39 | 40 | public: 41 | SourceJavaScriptPreparation( 42 | std::shared_ptr buf, 43 | std::string sourceURL) 44 | : buf_(std::move(buf)), sourceURL_(std::move(sourceURL)) {} 45 | 46 | const std::string& sourceURL() const { 47 | return sourceURL_; 48 | } 49 | 50 | size_t size() const override { 51 | return buf_->size(); 52 | } 53 | const uint8_t* data() const override { 54 | return buf_->data(); 55 | } 56 | }; 57 | 58 | } // namespace jsi 59 | } // namespace facebook 60 | -------------------------------------------------------------------------------- /src/jsi/test/testlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace facebook { 18 | namespace jsi { 19 | 20 | class Runtime; 21 | 22 | using RuntimeFactory = std::function()>; 23 | 24 | std::vector runtimeGenerators(); 25 | 26 | class JSITestBase : public ::testing::TestWithParam { 27 | public: 28 | JSITestBase() : factory(GetParam()), runtime(factory()), rt(*runtime) {} 29 | 30 | Value eval(const char* code) { 31 | return rt.global().getPropertyAsFunction(rt, "eval").call(rt, code); 32 | } 33 | 34 | Function function(const std::string& code) { 35 | return eval(("(" + code + ")").c_str()).getObject(rt).getFunction(rt); 36 | } 37 | 38 | bool checkValue(const Value& value, const std::string& jsValue) { 39 | return function("function(value) { return value == " + jsValue + "; }") 40 | .call(rt, std::move(value)) 41 | .getBool(); 42 | } 43 | 44 | RuntimeFactory factory; 45 | std::unique_ptr runtime; 46 | Runtime& rt; 47 | }; 48 | } // namespace jsi 49 | } // namespace facebook 50 | -------------------------------------------------------------------------------- /src/jsi/threadsafe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace facebook { 16 | namespace jsi { 17 | 18 | class ThreadSafeRuntime : public Runtime { 19 | public: 20 | virtual void lock() const = 0; 21 | virtual void unlock() const = 0; 22 | virtual Runtime& getUnsafeRuntime() = 0; 23 | }; 24 | 25 | namespace detail { 26 | 27 | template 28 | struct WithLock { 29 | L lock; 30 | WithLock(R& r) : lock(r) {} 31 | void before() { 32 | lock.lock(); 33 | } 34 | void after() { 35 | lock.unlock(); 36 | } 37 | }; 38 | 39 | // The actual implementation of a given ThreadSafeRuntime. It's parameterized 40 | // by: 41 | // 42 | // - R: The actual Runtime type that this wraps 43 | // - L: A lock type that has three members: 44 | // - L(R& r) // ctor 45 | // - void lock() 46 | // - void unlock() 47 | template 48 | class ThreadSafeRuntimeImpl final 49 | : public WithRuntimeDecorator, R, ThreadSafeRuntime> { 50 | public: 51 | template 52 | ThreadSafeRuntimeImpl(Args&&... args) 53 | : WithRuntimeDecorator, R, ThreadSafeRuntime>( 54 | unsafe_, 55 | lock_), 56 | unsafe_(std::forward(args)...), 57 | lock_(unsafe_) {} 58 | 59 | R& getUnsafeRuntime() override { 60 | return WithRuntimeDecorator, R, ThreadSafeRuntime>::plain(); 61 | } 62 | 63 | void lock() const override { 64 | lock_.before(); 65 | } 66 | 67 | void unlock() const override { 68 | lock_.after(); 69 | } 70 | 71 | private: 72 | R unsafe_; 73 | mutable WithLock lock_; 74 | }; 75 | 76 | } // namespace detail 77 | 78 | } // namespace jsi 79 | } // namespace facebook 80 | -------------------------------------------------------------------------------- /src/makev8jsi.lst: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | _ZN9v8runtime13makeV8RuntimeEONS_13V8RuntimeArgsE; 4 | local: 5 | *; 6 | }; -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/JSRuntimeApi.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #ifndef APILOADERS_JSRUNTIMEAPI_H_ 5 | #define APILOADERS_JSRUNTIMEAPI_H_ 6 | 7 | #include 8 | #include "NodeApi.h" 9 | 10 | namespace Microsoft::NodeApiJsi { 11 | 12 | class JSRuntimeApi : public NodeApi { 13 | public: 14 | JSRuntimeApi(IFuncResolver *funcResolver); 15 | 16 | static JSRuntimeApi *current() { 17 | return current_; 18 | } 19 | 20 | static void setCurrent(JSRuntimeApi *current) { 21 | NodeApi::setCurrent(current); 22 | current_ = current; 23 | } 24 | 25 | class Scope : public NodeApi::Scope { 26 | public: 27 | Scope(JSRuntimeApi *api) : NodeApi::Scope(api), prevJSRuntimeApi_(JSRuntimeApi::current_) { 28 | JSRuntimeApi::current_ = api; 29 | } 30 | 31 | ~Scope() { 32 | JSRuntimeApi::current_ = prevJSRuntimeApi_; 33 | } 34 | 35 | private: 36 | JSRuntimeApi *prevJSRuntimeApi_; 37 | }; 38 | 39 | public: 40 | #define JSR_FUNC(func) decltype(::func) *const func; 41 | #define JSR_JSI_FUNC JSR_FUNC 42 | #define JSR_PREPARED_SCRIPT JSR_FUNC 43 | #include "JSRuntimeApi.inc" 44 | 45 | private: 46 | static thread_local JSRuntimeApi *current_; 47 | }; 48 | 49 | } // namespace Microsoft::NodeApiJsi 50 | 51 | #endif // !APILOADERS_JSRUNTIMEAPI_H_ 52 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/JSRuntimeApi.inc: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #ifndef JSR_FUNC 5 | #define JSR_FUNC(func) 6 | #endif 7 | 8 | #ifndef JSR_JSI_FUNC 9 | #define JSR_JSI_FUNC(func) 10 | #endif 11 | 12 | #ifndef JSR_PREPARED_SCRIPT 13 | #define JSR_PREPARED_SCRIPT(func) 14 | #endif 15 | 16 | // The JS runtime functions sorted alphabetically. 17 | JSR_FUNC(jsr_collect_garbage) 18 | JSR_FUNC(jsr_config_enable_gc_api) 19 | JSR_FUNC(jsr_config_enable_inspector) 20 | JSR_FUNC(jsr_config_set_inspector_break_on_start) 21 | JSR_FUNC(jsr_config_set_inspector_port) 22 | JSR_FUNC(jsr_config_set_inspector_runtime_name) 23 | JSR_FUNC(jsr_config_set_script_cache) 24 | JSR_FUNC(jsr_config_set_task_runner) 25 | JSR_FUNC(jsr_create_config) 26 | JSR_FUNC(jsr_create_runtime) 27 | JSR_FUNC(jsr_delete_config) 28 | JSR_FUNC(jsr_delete_runtime) 29 | JSR_FUNC(jsr_get_and_clear_last_unhandled_promise_rejection) 30 | JSR_FUNC(jsr_has_unhandled_promise_rejection) 31 | JSR_FUNC(jsr_run_script) 32 | JSR_FUNC(jsr_runtime_get_node_api_env) 33 | 34 | // The JS runtime functions needed for JSI. 35 | JSR_JSI_FUNC(jsr_close_napi_env_scope) 36 | JSR_JSI_FUNC(jsr_queue_microtask) 37 | JSR_JSI_FUNC(jsr_drain_microtasks) 38 | JSR_JSI_FUNC(jsr_get_description) 39 | JSR_JSI_FUNC(jsr_is_inspectable) 40 | JSR_JSI_FUNC(jsr_open_napi_env_scope) 41 | 42 | JSR_JSI_FUNC(jsr_instrumentation_get_gc_stats) 43 | JSR_JSI_FUNC(jsr_instrumentation_get_heap_info) 44 | JSR_JSI_FUNC(jsr_instrumentation_collect_garbage) 45 | JSR_JSI_FUNC(jsr_instrumentation_start_heap_sampling) 46 | JSR_JSI_FUNC(jsr_instrumentation_stop_heap_sampling) 47 | JSR_JSI_FUNC(jsr_instrumentation_create_heap_snapshot) 48 | 49 | // The JS runtime functions needed for prepared script. 50 | JSR_PREPARED_SCRIPT(jsr_create_prepared_script) 51 | JSR_PREPARED_SCRIPT(jsr_delete_prepared_script) 52 | JSR_PREPARED_SCRIPT(jsr_prepared_script_run) 53 | 54 | #undef JSR_FUNC 55 | #undef JSR_JSI_FUNC 56 | #undef JSR_PREPARED_SCRIPT -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/NodeApi.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include "NodeApi.h" 5 | 6 | namespace Microsoft::NodeApiJsi { 7 | 8 | namespace { 9 | 10 | struct NodeApiNames { 11 | #define NODE_API_FUNC(func) static constexpr const char func[] = #func; 12 | #include "NodeApi.inc" 13 | }; 14 | 15 | } // namespace 16 | 17 | LibFuncResolver::LibFuncResolver(const char *libName) : libHandle_(LibLoader::loadLib(libName)) {} 18 | 19 | FuncPtr LibFuncResolver::getFuncPtr(const char *funcName) { 20 | return LibLoader::getFuncPtr(libHandle_, funcName); 21 | } 22 | 23 | DelayLoadedApi::DelayLoadedApi(IFuncResolver *funcResolver) : funcResolver_(funcResolver) {} 24 | 25 | DelayLoadedApi::~DelayLoadedApi() = default; 26 | 27 | FuncPtr DelayLoadedApi::getFuncPtr(const char *funcName) { 28 | return funcResolver_->getFuncPtr(funcName); 29 | } 30 | 31 | thread_local NodeApi *NodeApi::current_{}; 32 | 33 | NodeApi::NodeApi(IFuncResolver *funcResolver) 34 | : DelayLoadedApi(funcResolver) 35 | #define NODE_API_FUNC(func) \ 36 | , func(&ApiFuncResolver::stub) 37 | #include "NodeApi.inc" 38 | { 39 | } 40 | 41 | } // namespace Microsoft::NodeApiJsi 42 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/NodeApi_posix.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include "NodeApi.h" 5 | 6 | namespace Microsoft::NodeApiJsi { 7 | 8 | LibHandle LibLoader::loadLib(const char *libName) { 9 | // TODO: implement 10 | } 11 | 12 | FuncPtr LibLoader::getFuncPtr(LibHandle libHandle, const char *funcName) { 13 | // TODO: implement 14 | } 15 | 16 | } // namespace Microsoft::NodeApiJsi 17 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/NodeApi_win.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include "NodeApi.h" 5 | #ifndef WIN32_LEAN_AND_MEAN 6 | #define WIN32_LEAN_AND_MEAN 7 | #endif 8 | #ifndef NOMINMAX 9 | #define NOMINMAX 10 | #endif 11 | #include 12 | 13 | namespace Microsoft::NodeApiJsi { 14 | 15 | LibHandle LibLoader::loadLib(const char *libName) { 16 | return reinterpret_cast(LoadLibraryA(libName)); 17 | } 18 | 19 | FuncPtr LibLoader::getFuncPtr(LibHandle libHandle, const char *funcName) { 20 | return reinterpret_cast(GetProcAddress(reinterpret_cast(libHandle), funcName)); 21 | } 22 | 23 | } // namespace Microsoft::NodeApiJsi 24 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/V8Api.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include "V8Api.h" 5 | 6 | namespace Microsoft::NodeApiJsi { 7 | 8 | namespace { 9 | 10 | struct V8ApiNames { 11 | #define V8_FUNC(func) static constexpr const char func[] = #func; 12 | #include "V8Api.inc" 13 | }; 14 | 15 | } // namespace 16 | 17 | thread_local V8Api *V8Api::current_{}; 18 | 19 | V8Api::V8Api(IFuncResolver *funcResolver) 20 | : JSRuntimeApi(funcResolver) 21 | #define V8_FUNC(func) , func(&ApiFuncResolver::stub) 22 | #include "V8Api.inc" 23 | { 24 | } 25 | 26 | V8Api *V8Api::fromLib() { 27 | static LibFuncResolver funcResolver("v8jsi"); 28 | static V8Api *libV8Api = new V8Api(&funcResolver); 29 | return libV8Api; 30 | } 31 | 32 | } // namespace Microsoft::NodeApiJsi 33 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/V8Api.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | #ifndef APILOADERS_V8API_H_ 6 | #define APILOADERS_V8API_H_ 7 | 8 | #include 9 | #include "JSRuntimeApi.h" 10 | 11 | namespace Microsoft::NodeApiJsi { 12 | 13 | class V8Api : public JSRuntimeApi { 14 | public: 15 | V8Api(IFuncResolver *funcResolver); 16 | 17 | static V8Api *current() noexcept { 18 | return current_; 19 | } 20 | 21 | static void setCurrent(V8Api *current) noexcept { 22 | JSRuntimeApi::setCurrent(current); 23 | current_ = current; 24 | } 25 | 26 | static V8Api *fromLib(); 27 | 28 | class Scope : public JSRuntimeApi::Scope { 29 | public: 30 | Scope() : Scope(V8Api::fromLib()) {} 31 | 32 | Scope(V8Api *v8Api) : JSRuntimeApi::Scope(v8Api), prevV8Api_(V8Api::current_) { 33 | V8Api::current_ = v8Api; 34 | } 35 | 36 | ~Scope() { 37 | V8Api::current_ = prevV8Api_; 38 | } 39 | 40 | private: 41 | V8Api *prevV8Api_; 42 | }; 43 | 44 | public: 45 | #define V8_FUNC(func) decltype(::func) *const func; 46 | #include "V8Api.inc" 47 | 48 | private: 49 | static thread_local V8Api *current_; 50 | }; 51 | 52 | } // namespace Microsoft::NodeApiJsi 53 | 54 | #endif // !APILOADERS_V8API_H_ 55 | -------------------------------------------------------------------------------- /src/node-api-jsi/ApiLoaders/V8Api.inc: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #ifndef V8_FUNC 5 | #define V8_FUNC(func) 6 | #endif 7 | 8 | // The V8 runtime functions sorted alphabetically. 9 | V8_FUNC(v8_config_enable_multithreading) 10 | V8_FUNC(v8_platform_dispose) 11 | 12 | #undef V8_FUNC 13 | -------------------------------------------------------------------------------- /src/node-api-jsi/NodeApiJsiRuntime.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | #ifndef NODEAPIJSIRUNTIME_H_ 6 | #define NODEAPIJSIRUNTIME_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "ApiLoaders/JSRuntimeApi.h" 12 | 13 | namespace Microsoft::NodeApiJsi { 14 | 15 | std::unique_ptr 16 | makeNodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function onDelete) noexcept; 17 | 18 | struct NodeApiEnvScope { 19 | NodeApiEnvScope(napi_env env) : env_(env) { 20 | JSRuntimeApi::current()->jsr_open_napi_env_scope(env, &scope_); 21 | } 22 | 23 | NodeApiEnvScope(const NodeApiEnvScope &) = delete; 24 | NodeApiEnvScope &operator=(const NodeApiEnvScope &) = delete; 25 | 26 | ~NodeApiEnvScope() { 27 | JSRuntimeApi::current()->jsr_close_napi_env_scope(env_, scope_); 28 | } 29 | 30 | private: 31 | napi_env env_{}; 32 | jsr_napi_env_scope scope_{}; 33 | }; 34 | } // namespace Microsoft::NodeApiJsi 35 | 36 | #endif // !NODEAPIJSIRUNTIME_H_ 37 | -------------------------------------------------------------------------------- /src/node-api/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: Inline 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Attach 41 | BreakBeforeInheritanceComma: false 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakConstructorInitializers: BeforeColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 80 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^' 65 | Priority: 2 66 | - Regex: '^<.*\.h>' 67 | Priority: 1 68 | - Regex: '^<.*' 69 | Priority: 2 70 | - Regex: '.*' 71 | Priority: 3 72 | IncludeIsMainRegex: '([-_](test|unittest))?$' 73 | IndentCaseLabels: true 74 | IndentPPDirectives: None 75 | IndentWidth: 2 76 | IndentWrappedFunctionNames: false 77 | JavaScriptQuotes: Leave 78 | JavaScriptWrapImports: true 79 | KeepEmptyLinesAtTheStartOfBlocks: false 80 | MacroBlockBegin: '' 81 | MacroBlockEnd: '' 82 | MaxEmptyLinesToKeep: 1 83 | NamespaceIndentation: None 84 | ObjCBlockIndentWidth: 2 85 | ObjCSpaceAfterProperty: false 86 | ObjCSpaceBeforeProtocolList: false 87 | PenaltyBreakAssignment: 2 88 | PenaltyBreakBeforeFirstCallParameter: 1 89 | PenaltyBreakComment: 300 90 | PenaltyBreakFirstLessLess: 120 91 | PenaltyBreakString: 1000 92 | PenaltyExcessCharacter: 1000000 93 | PenaltyReturnTypeOnItsOwnLine: 200 94 | PointerAlignment: Left 95 | ReflowComments: true 96 | SortIncludes: true 97 | SortUsingDeclarations: true 98 | SpaceAfterCStyleCast: false 99 | SpaceAfterTemplateKeyword: true 100 | SpaceBeforeAssignmentOperators: true 101 | SpaceBeforeParens: ControlStatements 102 | SpaceInEmptyParentheses: false 103 | SpacesBeforeTrailingComments: 2 104 | SpacesInAngles: false 105 | SpacesInContainerLiterals: true 106 | SpacesInCStyleCastParentheses: false 107 | SpacesInParentheses: false 108 | SpacesInSquareBrackets: false 109 | Standard: Auto 110 | TabWidth: 8 111 | UseTab: Never 112 | -------------------------------------------------------------------------------- /src/node-api/env-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | // ---------------------------------------------------------------------------- 4 | // This file is referenced from js_native_api_v8.cc. 5 | // Most of code is removed or copied from other Node.js files to allow 6 | // the V8 NAPI code compilation without major changes. 7 | // ---------------------------------------------------------------------------- 8 | // Original Node.js copyright: 9 | // 10 | // Copyright Joyent, Inc. and other Node contributors. 11 | // 12 | // Permission is hereby granted, free of charge, to any person obtaining a 13 | // copy of this software and associated documentation files (the 14 | // "Software"), to deal in the Software without restriction, including 15 | // without limitation the rights to use, copy, modify, merge, publish, 16 | // distribute, sublicense, and/or sell copies of the Software, and to permit 17 | // persons to whom the Software is furnished to do so, subject to the 18 | // following conditions: 19 | // 20 | // The above copyright notice and this permission notice shall be included 21 | // in all copies or substantial portions of the Software. 22 | // 23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 24 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 26 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 27 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 28 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 29 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | #pragma once 32 | #ifndef SRC_ENV_INL_H_ 33 | #define SRC_ENV_INL_H_ 34 | 35 | // '!=': logical operation on address of string constant 36 | #pragma warning(disable : 4130) 37 | 38 | #endif // SRC_ENV_INL_H_ 39 | -------------------------------------------------------------------------------- /src/node-api/test/child_process.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | #ifndef CHILD_PROCESS_H_ 6 | #define CHILD_PROCESS_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace node_api_tests { 13 | 14 | struct ProcessResult { 15 | uint32_t status; 16 | std::string std_output; 17 | std::string std_error; 18 | }; 19 | 20 | ProcessResult spawnSync(std::string_view command, 21 | std::vector args); 22 | 23 | } // namespace node_api_tests 24 | 25 | #endif // !CHILD_PROCESS_H_ -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/.gitignore: -------------------------------------------------------------------------------- 1 | .buildstamp 2 | .docbuildstamp 3 | Makefile 4 | *.Makefile 5 | *.mk 6 | gyp-mac-tool 7 | /*/build 8 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/2_function_arguments/2_function_arguments.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value Add(napi_env env, napi_callback_info info) { 6 | size_t argc = 2; 7 | napi_value args[2]; 8 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 9 | 10 | NODE_API_ASSERT(env, argc >= 2, "Wrong number of arguments"); 11 | 12 | napi_valuetype valuetype0; 13 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0)); 14 | 15 | napi_valuetype valuetype1; 16 | NODE_API_CALL(env, napi_typeof(env, args[1], &valuetype1)); 17 | 18 | NODE_API_ASSERT(env, 19 | valuetype0 == napi_number && valuetype1 == napi_number, 20 | "Wrong argument type. Numbers expected."); 21 | 22 | double value0; 23 | NODE_API_CALL(env, napi_get_value_double(env, args[0], &value0)); 24 | 25 | double value1; 26 | NODE_API_CALL(env, napi_get_value_double(env, args[1], &value1)); 27 | 28 | napi_value sum; 29 | NODE_API_CALL(env, napi_create_double(env, value0 + value1, &sum)); 30 | 31 | return sum; 32 | } 33 | 34 | EXTERN_C_START 35 | napi_value Init(napi_env env, napi_value exports) { 36 | napi_property_descriptor desc = DECLARE_NODE_API_PROPERTY("add", Add); 37 | NODE_API_CALL(env, napi_define_properties(env, exports, 1, &desc)); 38 | return exports; 39 | } 40 | EXTERN_C_END 41 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/2_function_arguments/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "2_function_arguments", 5 | "sources": [ 6 | "2_function_arguments.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/2_function_arguments/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const addon = require(`./build/${common.buildType}/2_function_arguments`); 5 | 6 | assert.strictEqual(addon.add(3, 5), 8); 7 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/3_callbacks/3_callbacks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../common.h" 4 | #include "../entry_point.h" 5 | 6 | static napi_value RunCallback(napi_env env, napi_callback_info info) { 7 | size_t argc = 2; 8 | napi_value args[2]; 9 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 10 | 11 | NODE_API_ASSERT( 12 | env, argc == 1, "Wrong number of arguments. Expects a single argument."); 13 | 14 | napi_valuetype valuetype0; 15 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0)); 16 | NODE_API_ASSERT( 17 | env, 18 | valuetype0 == napi_function, 19 | "Wrong type of arguments. Expects a function as first argument."); 20 | 21 | napi_valuetype valuetype1; 22 | NODE_API_CALL(env, napi_typeof(env, args[1], &valuetype1)); 23 | NODE_API_ASSERT(env, 24 | valuetype1 == napi_undefined, 25 | "Additional arguments should be undefined."); 26 | 27 | napi_value argv[1]; 28 | const char* str = "hello world"; 29 | size_t str_len = strlen(str); 30 | NODE_API_CALL(env, napi_create_string_utf8(env, str, str_len, argv)); 31 | 32 | napi_value global; 33 | NODE_API_CALL(env, napi_get_global(env, &global)); 34 | 35 | napi_value cb = args[0]; 36 | NODE_API_CALL(env, napi_call_function(env, global, cb, 1, argv, NULL)); 37 | 38 | return NULL; 39 | } 40 | 41 | static napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { 42 | size_t argc = 2; 43 | napi_value args[2]; 44 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 45 | 46 | napi_value cb = args[0]; 47 | napi_value recv = args[1]; 48 | NODE_API_CALL(env, napi_call_function(env, recv, cb, 0, NULL, NULL)); 49 | return NULL; 50 | } 51 | 52 | EXTERN_C_START 53 | napi_value Init(napi_env env, napi_value exports) { 54 | napi_property_descriptor desc[2] = { 55 | DECLARE_NODE_API_PROPERTY("RunCallback", RunCallback), 56 | DECLARE_NODE_API_PROPERTY("RunCallbackWithRecv", RunCallbackWithRecv), 57 | }; 58 | NODE_API_CALL(env, napi_define_properties(env, exports, 2, desc)); 59 | return exports; 60 | } 61 | EXTERN_C_END 62 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/3_callbacks/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "3_callbacks", 5 | "sources": [ 6 | "3_callbacks.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/3_callbacks/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const addon = require(`./build/${common.buildType}/3_callbacks`); 5 | 6 | addon.RunCallback(function(msg) { 7 | assert.strictEqual(msg, 'hello world'); 8 | }); 9 | 10 | function testRecv(desiredRecv) { 11 | addon.RunCallbackWithRecv(function() { 12 | assert.strictEqual(this, desiredRecv); 13 | }, desiredRecv); 14 | } 15 | 16 | testRecv(undefined); 17 | testRecv(null); 18 | testRecv(5); 19 | testRecv(true); 20 | testRecv('Hello'); 21 | testRecv([]); 22 | testRecv({}); 23 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/4_object_factory/4_object_factory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value CreateObject(napi_env env, napi_callback_info info) { 6 | size_t argc = 1; 7 | napi_value args[1]; 8 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 9 | 10 | napi_value obj; 11 | NODE_API_CALL(env, napi_create_object(env, &obj)); 12 | 13 | NODE_API_CALL(env, napi_set_named_property(env, obj, "msg", args[0])); 14 | 15 | return obj; 16 | } 17 | 18 | EXTERN_C_START 19 | napi_value Init(napi_env env, napi_value exports) { 20 | NODE_API_CALL( 21 | env, 22 | napi_create_function(env, "exports", -1, CreateObject, NULL, &exports)); 23 | return exports; 24 | } 25 | EXTERN_C_END 26 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/4_object_factory/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "4_object_factory", 5 | "sources": [ 6 | "4_object_factory.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/4_object_factory/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const addon = require(`./build/${common.buildType}/4_object_factory`); 5 | 6 | const obj1 = addon('hello'); 7 | const obj2 = addon('world'); 8 | assert.strictEqual(`${obj1.msg} ${obj2.msg}`, 'hello world'); 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/5_function_factory/5_function_factory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value MyFunction(napi_env env, napi_callback_info info) { 6 | napi_value str; 7 | NODE_API_CALL(env, napi_create_string_utf8(env, "hello world", -1, &str)); 8 | return str; 9 | } 10 | 11 | static napi_value CreateFunction(napi_env env, napi_callback_info info) { 12 | napi_value fn; 13 | NODE_API_CALL( 14 | env, napi_create_function(env, "theFunction", -1, MyFunction, NULL, &fn)); 15 | return fn; 16 | } 17 | 18 | EXTERN_C_START 19 | napi_value Init(napi_env env, napi_value exports) { 20 | NODE_API_CALL( 21 | env, 22 | napi_create_function(env, "exports", -1, CreateFunction, NULL, &exports)); 23 | return exports; 24 | } 25 | EXTERN_C_END 26 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/5_function_factory/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "5_function_factory", 5 | "sources": [ 6 | "5_function_factory.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/5_function_factory/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const addon = require(`./build/${common.buildType}/5_function_factory`); 5 | 6 | const fn = addon(); 7 | assert.strictEqual(fn(), 'hello world'); // 'hello world' 8 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/6_object_wrap/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "6_object_wrap", 5 | "sources": [ 6 | "6_object_wrap.cc" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/6_object_wrap/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_6_OBJECT_WRAP_MYOBJECT_H_ 2 | #define TEST_JS_NATIVE_API_6_OBJECT_WRAP_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static void Init(napi_env env, napi_value exports); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | 11 | private: 12 | explicit MyObject(double value_ = 0); 13 | ~MyObject(); 14 | 15 | static napi_value New(napi_env env, napi_callback_info info); 16 | static napi_value GetValue(napi_env env, napi_callback_info info); 17 | static napi_value SetValue(napi_env env, napi_callback_info info); 18 | static napi_value PlusOne(napi_env env, napi_callback_info info); 19 | static napi_value Multiply(napi_env env, napi_callback_info info); 20 | static napi_ref constructor; 21 | double value_; 22 | napi_env env_; 23 | napi_ref wrapper_; 24 | }; 25 | 26 | #endif // TEST_JS_NATIVE_API_6_OBJECT_WRAP_MYOBJECT_H_ 27 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/6_object_wrap/test-object-wrap-ref.js: -------------------------------------------------------------------------------- 1 | // Flags: --expose-gc 2 | 3 | 'use strict'; 4 | const common = require('../../common'); 5 | const addon = require(`./build/${common.buildType}/6_object_wrap`); 6 | 7 | (function scope() { 8 | addon.objectWrapDanglingReference({}); 9 | })(); 10 | 11 | common.gcUntil('object-wrap-ref', () => { 12 | return addon.objectWrapDanglingReferenceTest(); 13 | }); 14 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/6_object_wrap/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const addon = require(`./build/${common.buildType}/6_object_wrap`); 5 | 6 | const getterOnlyErrorRE = 7 | /^TypeError: Cannot set property .* of #<.*> which has only a getter$/; 8 | 9 | const valueDescriptor = Object.getOwnPropertyDescriptor( 10 | addon.MyObject.prototype, 'value'); 11 | const valueReadonlyDescriptor = Object.getOwnPropertyDescriptor( 12 | addon.MyObject.prototype, 'valueReadonly'); 13 | const plusOneDescriptor = Object.getOwnPropertyDescriptor( 14 | addon.MyObject.prototype, 'plusOne'); 15 | assert.strictEqual(typeof valueDescriptor.get, 'function'); 16 | assert.strictEqual(typeof valueDescriptor.set, 'function'); 17 | assert.strictEqual(valueDescriptor.value, undefined); 18 | assert.strictEqual(valueDescriptor.enumerable, false); 19 | assert.strictEqual(valueDescriptor.configurable, false); 20 | assert.strictEqual(typeof valueReadonlyDescriptor.get, 'function'); 21 | assert.strictEqual(valueReadonlyDescriptor.set, undefined); 22 | assert.strictEqual(valueReadonlyDescriptor.value, undefined); 23 | assert.strictEqual(valueReadonlyDescriptor.enumerable, false); 24 | assert.strictEqual(valueReadonlyDescriptor.configurable, false); 25 | 26 | assert.strictEqual(plusOneDescriptor.get, undefined); 27 | assert.strictEqual(plusOneDescriptor.set, undefined); 28 | assert.strictEqual(typeof plusOneDescriptor.value, 'function'); 29 | assert.strictEqual(plusOneDescriptor.enumerable, false); 30 | assert.strictEqual(plusOneDescriptor.configurable, false); 31 | 32 | const obj = new addon.MyObject(9); 33 | assert.strictEqual(obj.value, 9); 34 | obj.value = 10; 35 | assert.strictEqual(obj.value, 10); 36 | assert.strictEqual(obj.valueReadonly, 10); 37 | assert.throws(() => { obj.valueReadonly = 14; }, getterOnlyErrorRE); 38 | assert.strictEqual(obj.plusOne(), 11); 39 | assert.strictEqual(obj.plusOne(), 12); 40 | assert.strictEqual(obj.plusOne(), 13); 41 | 42 | assert.strictEqual(obj.multiply().value, 13); 43 | assert.strictEqual(obj.multiply(10).value, 130); 44 | 45 | const newobj = obj.multiply(-1); 46 | assert.strictEqual(newobj.value, -13); 47 | assert.strictEqual(newobj.valueReadonly, -13); 48 | assert.notStrictEqual(obj, newobj); 49 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/7_factory_wrap/7_factory_wrap.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | #include "myobject.h" 5 | 6 | napi_value CreateObject(napi_env env, napi_callback_info info) { 7 | size_t argc = 1; 8 | napi_value args[1]; 9 | NODE_API_CALL(env, 10 | napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); 11 | 12 | napi_value instance; 13 | NODE_API_CALL(env, MyObject::NewInstance(env, args[0], &instance)); 14 | 15 | return instance; 16 | } 17 | 18 | EXTERN_C_START 19 | napi_value Init(napi_env env, napi_value exports) { 20 | NODE_API_CALL(env, MyObject::Init(env)); 21 | 22 | napi_property_descriptor descriptors[] = { 23 | DECLARE_NODE_API_GETTER("finalizeCount", MyObject::GetFinalizeCount), 24 | DECLARE_NODE_API_PROPERTY("createObject", CreateObject), 25 | }; 26 | 27 | NODE_API_CALL( 28 | env, 29 | napi_define_properties(env, 30 | exports, 31 | sizeof(descriptors) / sizeof(*descriptors), 32 | descriptors)); 33 | 34 | return exports; 35 | } 36 | EXTERN_C_END 37 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/7_factory_wrap/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "7_factory_wrap", 5 | "sources": [ 6 | "7_factory_wrap.cc", 7 | "myobject.cc" 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/7_factory_wrap/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include "../common.h" 3 | 4 | static int finalize_count = 0; 5 | 6 | MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} 7 | 8 | MyObject::~MyObject() { 9 | napi_delete_reference(env_, wrapper_); 10 | } 11 | 12 | void MyObject::Destructor(napi_env env, 13 | void* nativeObject, 14 | void* /*finalize_hint*/) { 15 | ++finalize_count; 16 | MyObject* obj = static_cast(nativeObject); 17 | delete obj; 18 | } 19 | 20 | napi_value MyObject::GetFinalizeCount(napi_env env, napi_callback_info info) { 21 | napi_value result; 22 | NODE_API_CALL(env, napi_create_int32(env, finalize_count, &result)); 23 | return result; 24 | } 25 | 26 | napi_ref MyObject::constructor; 27 | 28 | napi_status MyObject::Init(napi_env env) { 29 | napi_status status; 30 | napi_property_descriptor properties[] = { 31 | DECLARE_NODE_API_PROPERTY("plusOne", PlusOne), 32 | }; 33 | 34 | napi_value cons; 35 | status = napi_define_class( 36 | env, "MyObject", -1, New, nullptr, 1, properties, &cons); 37 | if (status != napi_ok) return status; 38 | 39 | status = napi_create_reference(env, cons, 1, &constructor); 40 | if (status != napi_ok) return status; 41 | 42 | return napi_ok; 43 | } 44 | 45 | napi_value MyObject::New(napi_env env, napi_callback_info info) { 46 | size_t argc = 1; 47 | napi_value args[1]; 48 | napi_value _this; 49 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr)); 50 | 51 | napi_valuetype valuetype; 52 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype)); 53 | 54 | MyObject* obj = new MyObject(); 55 | 56 | if (valuetype == napi_undefined) { 57 | obj->counter_ = 0; 58 | } else { 59 | NODE_API_CALL(env, napi_get_value_uint32(env, args[0], &obj->counter_)); 60 | } 61 | 62 | obj->env_ = env; 63 | NODE_API_CALL(env, 64 | napi_wrap(env, 65 | _this, 66 | obj, 67 | MyObject::Destructor, 68 | nullptr /* finalize_hint */, 69 | &obj->wrapper_)); 70 | 71 | return _this; 72 | } 73 | 74 | napi_status MyObject::NewInstance(napi_env env, 75 | napi_value arg, 76 | napi_value* instance) { 77 | napi_status status; 78 | 79 | const int argc = 1; 80 | napi_value argv[argc] = {arg}; 81 | 82 | napi_value cons; 83 | status = napi_get_reference_value(env, constructor, &cons); 84 | if (status != napi_ok) return status; 85 | 86 | status = napi_new_instance(env, cons, argc, argv, instance); 87 | if (status != napi_ok) return status; 88 | 89 | return napi_ok; 90 | } 91 | 92 | napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) { 93 | napi_value _this; 94 | NODE_API_CALL(env, 95 | napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr)); 96 | 97 | MyObject* obj; 98 | NODE_API_CALL(env, napi_unwrap(env, _this, reinterpret_cast(&obj))); 99 | 100 | obj->counter_ += 1; 101 | 102 | napi_value num; 103 | NODE_API_CALL(env, napi_create_uint32(env, obj->counter_, &num)); 104 | 105 | return num; 106 | } 107 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/7_factory_wrap/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_7_FACTORY_WRAP_MYOBJECT_H_ 2 | #define TEST_JS_NATIVE_API_7_FACTORY_WRAP_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static napi_status Init(napi_env env); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | static napi_value GetFinalizeCount(napi_env env, napi_callback_info info); 11 | static napi_status NewInstance(napi_env env, 12 | napi_value arg, 13 | napi_value* instance); 14 | 15 | private: 16 | MyObject(); 17 | ~MyObject(); 18 | 19 | static napi_ref constructor; 20 | static napi_value New(napi_env env, napi_callback_info info); 21 | static napi_value PlusOne(napi_env env, napi_callback_info info); 22 | uint32_t counter_; 23 | napi_env env_; 24 | napi_ref wrapper_; 25 | }; 26 | 27 | #endif // TEST_JS_NATIVE_API_7_FACTORY_WRAP_MYOBJECT_H_ 28 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/7_factory_wrap/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const assert = require('assert'); 6 | const test = require(`./build/${common.buildType}/7_factory_wrap`); 7 | 8 | assert.strictEqual(test.finalizeCount, 0); 9 | async function runGCTests() { 10 | (() => { 11 | const obj = test.createObject(10); 12 | assert.strictEqual(obj.plusOne(), 11); 13 | assert.strictEqual(obj.plusOne(), 12); 14 | assert.strictEqual(obj.plusOne(), 13); 15 | })(); 16 | await common.gcUntil('test 1', () => (test.finalizeCount === 1)); 17 | 18 | (() => { 19 | const obj2 = test.createObject(20); 20 | assert.strictEqual(obj2.plusOne(), 21); 21 | assert.strictEqual(obj2.plusOne(), 22); 22 | assert.strictEqual(obj2.plusOne(), 23); 23 | })(); 24 | await common.gcUntil('test 2', () => (test.finalizeCount === 2)); 25 | } 26 | runGCTests(); 27 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/8_passing_wrapped/8_passing_wrapped.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | #include "myobject.h" 5 | 6 | extern size_t finalize_count; 7 | 8 | static napi_value CreateObject(napi_env env, napi_callback_info info) { 9 | size_t argc = 1; 10 | napi_value args[1]; 11 | NODE_API_CALL(env, 12 | napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); 13 | 14 | napi_value instance; 15 | NODE_API_CALL(env, MyObject::NewInstance(env, args[0], &instance)); 16 | 17 | return instance; 18 | } 19 | 20 | static napi_value Add(napi_env env, napi_callback_info info) { 21 | size_t argc = 2; 22 | napi_value args[2]; 23 | NODE_API_CALL(env, 24 | napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); 25 | 26 | MyObject* obj1; 27 | NODE_API_CALL(env, 28 | napi_unwrap(env, args[0], reinterpret_cast(&obj1))); 29 | 30 | MyObject* obj2; 31 | NODE_API_CALL(env, 32 | napi_unwrap(env, args[1], reinterpret_cast(&obj2))); 33 | 34 | napi_value sum; 35 | NODE_API_CALL(env, napi_create_double(env, obj1->Val() + obj2->Val(), &sum)); 36 | 37 | return sum; 38 | } 39 | 40 | static napi_value FinalizeCount(napi_env env, napi_callback_info info) { 41 | napi_value return_value; 42 | NODE_API_CALL(env, napi_create_uint32(env, finalize_count, &return_value)); 43 | return return_value; 44 | } 45 | 46 | EXTERN_C_START 47 | napi_value Init(napi_env env, napi_value exports) { 48 | MyObject::Init(env); 49 | 50 | napi_property_descriptor desc[] = { 51 | DECLARE_NODE_API_PROPERTY("createObject", CreateObject), 52 | DECLARE_NODE_API_PROPERTY("add", Add), 53 | DECLARE_NODE_API_PROPERTY("finalizeCount", FinalizeCount), 54 | }; 55 | 56 | NODE_API_CALL( 57 | env, 58 | napi_define_properties(env, exports, sizeof(desc) / sizeof(*desc), desc)); 59 | 60 | return exports; 61 | } 62 | EXTERN_C_END 63 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/8_passing_wrapped/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "8_passing_wrapped", 5 | "sources": [ 6 | "8_passing_wrapped.cc", 7 | "myobject.cc" 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/8_passing_wrapped/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include "../common.h" 3 | 4 | size_t finalize_count = 0; 5 | 6 | MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} 7 | 8 | MyObject::~MyObject() { 9 | finalize_count++; 10 | napi_delete_reference(env_, wrapper_); 11 | } 12 | 13 | void MyObject::Destructor(napi_env env, 14 | void* nativeObject, 15 | void* /*finalize_hint*/) { 16 | MyObject* obj = static_cast(nativeObject); 17 | delete obj; 18 | } 19 | 20 | napi_ref MyObject::constructor; 21 | 22 | napi_status MyObject::Init(napi_env env) { 23 | napi_status status; 24 | 25 | napi_value cons; 26 | status = 27 | napi_define_class(env, "MyObject", -1, New, nullptr, 0, nullptr, &cons); 28 | if (status != napi_ok) return status; 29 | 30 | status = napi_create_reference(env, cons, 1, &constructor); 31 | if (status != napi_ok) return status; 32 | 33 | return napi_ok; 34 | } 35 | 36 | napi_value MyObject::New(napi_env env, napi_callback_info info) { 37 | size_t argc = 1; 38 | napi_value args[1]; 39 | napi_value _this; 40 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr)); 41 | 42 | MyObject* obj = new MyObject(); 43 | 44 | napi_valuetype valuetype; 45 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype)); 46 | 47 | if (valuetype == napi_undefined) { 48 | obj->val_ = 0; 49 | } else { 50 | NODE_API_CALL(env, napi_get_value_double(env, args[0], &obj->val_)); 51 | } 52 | 53 | obj->env_ = env; 54 | 55 | // The below call to napi_wrap() must request a reference to the wrapped 56 | // object via the out-parameter, because this ensures that we test the code 57 | // path that deals with a reference that is destroyed from its own finalizer. 58 | NODE_API_CALL(env, 59 | napi_wrap(env, 60 | _this, 61 | obj, 62 | MyObject::Destructor, 63 | nullptr /* finalize_hint */, 64 | &obj->wrapper_)); 65 | 66 | return _this; 67 | } 68 | 69 | napi_status MyObject::NewInstance(napi_env env, 70 | napi_value arg, 71 | napi_value* instance) { 72 | napi_status status; 73 | 74 | const int argc = 1; 75 | napi_value argv[argc] = {arg}; 76 | 77 | napi_value cons; 78 | status = napi_get_reference_value(env, constructor, &cons); 79 | if (status != napi_ok) return status; 80 | 81 | status = napi_new_instance(env, cons, argc, argv, instance); 82 | if (status != napi_ok) return status; 83 | 84 | return napi_ok; 85 | } 86 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/8_passing_wrapped/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_8_PASSING_WRAPPED_MYOBJECT_H_ 2 | #define TEST_JS_NATIVE_API_8_PASSING_WRAPPED_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static napi_status Init(napi_env env); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | static napi_status NewInstance(napi_env env, 11 | napi_value arg, 12 | napi_value* instance); 13 | double Val() const { return val_; } 14 | 15 | private: 16 | MyObject(); 17 | ~MyObject(); 18 | 19 | static napi_ref constructor; 20 | static napi_value New(napi_env env, napi_callback_info info); 21 | double val_; 22 | napi_env env_; 23 | napi_ref wrapper_; 24 | }; 25 | 26 | #endif // TEST_JS_NATIVE_API_8_PASSING_WRAPPED_MYOBJECT_H_ 27 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/8_passing_wrapped/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const assert = require('assert'); 6 | const addon = require(`./build/${common.buildType}/8_passing_wrapped`); 7 | 8 | async function runTest() { 9 | let obj1 = addon.createObject(10); 10 | let obj2 = addon.createObject(20); 11 | const result = addon.add(obj1, obj2); 12 | assert.strictEqual(result, 30); 13 | 14 | // Make sure the native destructor gets called. 15 | obj1 = null; 16 | obj2 = null; 17 | await common.gcUntil('8_passing_wrapped', 18 | () => (addon.finalizeCount() === 2)); 19 | } 20 | runTest(); 21 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/common-inl.h: -------------------------------------------------------------------------------- 1 | #ifndef JS_NATIVE_API_COMMON_INL_H_ 2 | #define JS_NATIVE_API_COMMON_INL_H_ 3 | 4 | #include 5 | #include "common.h" 6 | 7 | #include 8 | 9 | inline void add_returned_status(napi_env env, 10 | const char* key, 11 | napi_value object, 12 | char* expected_message, 13 | napi_status expected_status, 14 | napi_status actual_status) { 15 | char napi_message_string[100] = ""; 16 | napi_value prop_value; 17 | 18 | if (actual_status != expected_status) { 19 | snprintf(napi_message_string, 20 | sizeof(napi_message_string), 21 | "Invalid status [%d]", 22 | actual_status); 23 | } 24 | 25 | NODE_API_CALL_RETURN_VOID( 26 | env, 27 | napi_create_string_utf8( 28 | env, 29 | (actual_status == expected_status ? expected_message 30 | : napi_message_string), 31 | NAPI_AUTO_LENGTH, 32 | &prop_value)); 33 | NODE_API_CALL_RETURN_VOID( 34 | env, napi_set_named_property(env, object, key, prop_value)); 35 | } 36 | 37 | inline void add_last_status(napi_env env, 38 | const char* key, 39 | napi_value return_value) { 40 | napi_value prop_value; 41 | napi_value exception; 42 | const napi_extended_error_info* p_last_error; 43 | NODE_API_CALL_RETURN_VOID(env, napi_get_last_error_info(env, &p_last_error)); 44 | // Content of p_last_error can be updated in subsequent node-api calls. 45 | // Retrieve it immediately. 46 | const char* error_message = p_last_error->error_message == NULL 47 | ? "napi_ok" 48 | : p_last_error->error_message; 49 | 50 | bool is_exception_pending; 51 | NODE_API_CALL_RETURN_VOID( 52 | env, napi_is_exception_pending(env, &is_exception_pending)); 53 | if (is_exception_pending) { 54 | NODE_API_CALL_RETURN_VOID( 55 | env, napi_get_and_clear_last_exception(env, &exception)); 56 | char exception_key[50]; 57 | snprintf(exception_key, sizeof(exception_key), "%s%s", key, "Exception"); 58 | NODE_API_CALL_RETURN_VOID( 59 | env, 60 | napi_set_named_property(env, return_value, exception_key, exception)); 61 | } 62 | 63 | NODE_API_CALL_RETURN_VOID( 64 | env, 65 | napi_create_string_utf8( 66 | env, error_message, NAPI_AUTO_LENGTH, &prop_value)); 67 | NODE_API_CALL_RETURN_VOID( 68 | env, napi_set_named_property(env, return_value, key, prop_value)); 69 | } 70 | 71 | #endif // JS_NATIVE_API_COMMON_INL_H_ 72 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/common/common.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | // 4 | // The JavaScript code in this file is adopted from the Node.js project. 5 | // See the src\napi\Readme.md about the Node.js copyright notice. 6 | 'use strict'; 7 | 8 | const { mustCall, mustCallAtLeast, mustNotCall } = require('assert'); 9 | 10 | const buildType = 'x86'; 11 | 12 | const isWindows = true; //TODO: process.platform === 'win32'; 13 | 14 | function gcUntil(name, condition) { 15 | if (typeof name === 'function') { 16 | condition = name; 17 | name = undefined; 18 | } 19 | return new Promise((resolve, reject) => { 20 | let count = 0; 21 | function gcAndCheck() { 22 | setImmediate(() => { 23 | count++; 24 | global.gc(); 25 | if (condition()) { 26 | resolve(); 27 | } else if (count < 10) { 28 | gcAndCheck(); 29 | } else { 30 | reject(name === undefined ? undefined : 'Test ' + name + ' failed'); 31 | } 32 | }); 33 | } 34 | gcAndCheck(); 35 | }); 36 | } 37 | 38 | // Returns true if the exit code "exitCode" and/or signal name "signal" 39 | // represent the exit code and/or signal name of a node process that aborted, 40 | // false otherwise. 41 | function nodeProcessAborted(exitCode, signal) { 42 | // Depending on the compiler used, node will exit with either 43 | // exit code 132 (SIGILL), 133 (SIGTRAP) or 134 (SIGABRT). 44 | let expectedExitCodes = [132, 133, 134]; 45 | 46 | // On platforms using KSH as the default shell (like SmartOS), 47 | // when a process aborts, KSH exits with an exit code that is 48 | // greater than 256, and thus the exit code emitted with the 'exit' 49 | // event is null and the signal is set to either SIGILL, SIGTRAP, 50 | // or SIGABRT (depending on the compiler). 51 | const expectedSignals = ['SIGILL', 'SIGTRAP', 'SIGABRT']; 52 | 53 | // On Windows, 'aborts' are of 2 types, depending on the context: 54 | // (i) Exception breakpoint, if --abort-on-uncaught-exception is on 55 | // which corresponds to exit code 2147483651 (0x80000003) 56 | // (ii) Otherwise, _exit(134) which is called in place of abort() due to 57 | // raising SIGABRT exiting with ambiguous exit code '3' by default 58 | if (isWindows) 59 | expectedExitCodes = [0x80000003, 134]; 60 | 61 | // When using --abort-on-uncaught-exception, V8 will use 62 | // base::OS::Abort to terminate the process. 63 | // Depending on the compiler used, the shell or other aspects of 64 | // the platform used to build the node binary, this will actually 65 | // make V8 exit by aborting or by raising a signal. In any case, 66 | // one of them (exit code or signal) needs to be set to one of 67 | // the expected exit codes or signals. 68 | if (signal !== null) { 69 | return expectedSignals.includes(signal); 70 | } 71 | return expectedExitCodes.includes(exitCode); 72 | } 73 | 74 | Object.assign(module.exports, { 75 | buildType, 76 | gcUntil, 77 | mustCall, 78 | mustCallAtLeast, 79 | mustNotCall, 80 | nodeProcessAborted, 81 | }); 82 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/entry_point.h: -------------------------------------------------------------------------------- 1 | #ifndef JS_NATIVE_API_ENTRY_POINT_H_ 2 | #define JS_NATIVE_API_ENTRY_POINT_H_ 3 | 4 | #include 5 | 6 | EXTERN_C_START 7 | napi_value Init(napi_env env, napi_value exports); 8 | EXTERN_C_END 9 | 10 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 11 | 12 | #endif // JS_NATIVE_API_ENTRY_POINT_H_ 13 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/node_api_types.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_NODE_API_TYPES_H_ 2 | #define SRC_NODE_API_TYPES_H_ 3 | 4 | #include "js_native_api_types.h" 5 | 6 | typedef struct napi_callback_scope__* napi_callback_scope; 7 | typedef struct napi_async_context__* napi_async_context; 8 | typedef struct napi_async_work__* napi_async_work; 9 | 10 | #if NAPI_VERSION >= 3 11 | typedef void(NAPI_CDECL* napi_cleanup_hook)(void* arg); 12 | #endif // NAPI_VERSION >= 3 13 | 14 | #if NAPI_VERSION >= 4 15 | typedef struct napi_threadsafe_function__* napi_threadsafe_function; 16 | #endif // NAPI_VERSION >= 4 17 | 18 | #if NAPI_VERSION >= 4 19 | typedef enum { 20 | napi_tsfn_release, 21 | napi_tsfn_abort 22 | } napi_threadsafe_function_release_mode; 23 | 24 | typedef enum { 25 | napi_tsfn_nonblocking, 26 | napi_tsfn_blocking 27 | } napi_threadsafe_function_call_mode; 28 | #endif // NAPI_VERSION >= 4 29 | 30 | typedef void(NAPI_CDECL* napi_async_execute_callback)(napi_env env, void* data); 31 | typedef void(NAPI_CDECL* napi_async_complete_callback)(napi_env env, 32 | napi_status status, 33 | void* data); 34 | #if NAPI_VERSION >= 4 35 | typedef void(NAPI_CDECL* napi_threadsafe_function_call_js)( 36 | napi_env env, napi_value js_callback, void* context, void* data); 37 | #endif // NAPI_VERSION >= 4 38 | 39 | typedef struct { 40 | uint32_t major; 41 | uint32_t minor; 42 | uint32_t patch; 43 | const char* release; 44 | } napi_node_version; 45 | 46 | #if NAPI_VERSION >= 8 47 | typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; 48 | typedef void(NAPI_CDECL* napi_async_cleanup_hook)( 49 | napi_async_cleanup_hook_handle handle, void* data); 50 | #endif // NAPI_VERSION >= 8 51 | 52 | #endif // SRC_NODE_API_TYPES_H_ 53 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_array/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_array", 5 | "sources": [ 6 | "test_array.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_array/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for arrays 6 | const test_array = require(`./build/${common.buildType}/test_array`); 7 | 8 | const array = [ 9 | 1, 10 | 9, 11 | 48, 12 | 13493, 13 | 9459324, 14 | { name: 'hello' }, 15 | [ 16 | 'world', 17 | 'node', 18 | 'abi', 19 | ], 20 | ]; 21 | 22 | assert.throws( 23 | () => { 24 | test_array.TestGetElement(array, array.length + 1); 25 | }, 26 | /^Error: assertion \(\(\(uint32_t\)index < length\)\) failed: Index out of bounds!$/, 27 | ); 28 | 29 | assert.throws( 30 | () => { 31 | test_array.TestGetElement(array, -2); 32 | }, 33 | /^Error: assertion \(index >= 0\) failed: Invalid index\. Expects a positive integer\.$/, 34 | ); 35 | 36 | array.forEach(function(element, index) { 37 | assert.strictEqual(test_array.TestGetElement(array, index), element); 38 | }); 39 | 40 | 41 | assert.deepStrictEqual(test_array.New(array), array); 42 | 43 | assert(test_array.TestHasElement(array, 0)); 44 | assert.strictEqual(test_array.TestHasElement(array, array.length + 1), false); 45 | 46 | assert(test_array.NewWithLength(0) instanceof Array); 47 | assert(test_array.NewWithLength(1) instanceof Array); 48 | // Check max allowed length for an array 2^32 -1 49 | assert(test_array.NewWithLength(4294967295) instanceof Array); 50 | 51 | { 52 | // Verify that array elements can be deleted. 53 | const arr = ['a', 'b', 'c', 'd']; 54 | 55 | assert.strictEqual(arr.length, 4); 56 | assert.strictEqual(2 in arr, true); 57 | assert.strictEqual(test_array.TestDeleteElement(arr, 2), true); 58 | assert.strictEqual(arr.length, 4); 59 | assert.strictEqual(2 in arr, false); 60 | } 61 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_bigint/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_bigint", 5 | "sources": [ 6 | "test_bigint.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_bigint/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const { 5 | IsLossless, 6 | TestInt64, 7 | TestUint64, 8 | TestWords, 9 | CreateTooBigBigInt, 10 | MakeBigIntWordsThrow, 11 | } = require(`./build/${common.buildType}/test_bigint`); 12 | 13 | [ 14 | 0n, 15 | -0n, 16 | 1n, 17 | -1n, 18 | 100n, 19 | 2121n, 20 | -1233n, 21 | 986583n, 22 | -976675n, 23 | 98765432213456789876546896323445679887645323232436587988766545658n, 24 | -4350987086545760976737453646576078997096876957864353245245769809n, 25 | ].forEach((num) => { 26 | if (num > -(2n ** 63n) && num < 2n ** 63n) { 27 | assert.strictEqual(TestInt64(num), num); 28 | assert.strictEqual(IsLossless(num, true), true); 29 | } else { 30 | assert.strictEqual(IsLossless(num, true), false); 31 | } 32 | 33 | if (num >= 0 && num < 2n ** 64n) { 34 | assert.strictEqual(TestUint64(num), num); 35 | assert.strictEqual(IsLossless(num, false), true); 36 | } else { 37 | assert.strictEqual(IsLossless(num, false), false); 38 | } 39 | 40 | assert.strictEqual(num, TestWords(num)); 41 | }); 42 | 43 | assert.throws(() => CreateTooBigBigInt(), { 44 | name: 'Error', 45 | message: 'Invalid argument', 46 | }); 47 | 48 | // Test that we correctly forward exceptions from the engine. 49 | assert.throws(() => MakeBigIntWordsThrow(), { 50 | name: 'RangeError', 51 | message: 'Maximum BigInt size exceeded', 52 | }); 53 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_cannot_run_js/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_cannot_run_js", 5 | "sources": [ 6 | "test_cannot_run_js.c" 7 | ], 8 | "defines": [ "NAPI_EXPERIMENTAL" ], 9 | }, 10 | { 11 | "target_name": "test_pending_exception", 12 | "sources": [ 13 | "test_cannot_run_js.c" 14 | ], 15 | "defines": [ "NAPI_VERSION=8" ], 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_cannot_run_js/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Test that `napi_call_function()` returns `napi_cannot_run_js` in experimental 4 | // mode and `napi_pending_exception` otherwise. This test calls the add-on's 5 | // `createRef()` method, which creates a strong reference to a JS function. When 6 | // the process exits, it calls all reference finalizers. The finalizer for the 7 | // strong reference created herein will attempt to call `napi_get_property()` on 8 | // a property of the global object and will abort the process if the API doesn't 9 | // return the correct status. 10 | 11 | const { buildType, mustNotCall } = require('../../common'); 12 | const addon_v8 = require(`./build/${buildType}/test_pending_exception`); 13 | const addon_new = require(`./build/${buildType}/test_cannot_run_js`); 14 | 15 | function runTests(addon, isVersion8) { 16 | addon.createRef(mustNotCall()); 17 | } 18 | 19 | function runAllTests() { 20 | runTests(addon_v8, /* isVersion8 */ true); 21 | runTests(addon_new, /* isVersion8 */ false); 22 | } 23 | 24 | runAllTests(); 25 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_cannot_run_js/test_cannot_run_js.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | #include "stdlib.h" 5 | 6 | static void Finalize(napi_env env, void* data, void* hint) { 7 | napi_value global, set_timeout; 8 | napi_ref* ref = data; 9 | 10 | NODE_API_NOGC_ASSERT_RETURN_VOID( 11 | napi_delete_reference(env, *ref) == napi_ok, 12 | "deleting reference in finalizer should succeed"); 13 | NODE_API_NOGC_ASSERT_RETURN_VOID( 14 | napi_get_global(env, &global) == napi_ok, 15 | "getting global reference in finalizer should succeed"); 16 | napi_status result = 17 | napi_get_named_property(env, global, "setTimeout", &set_timeout); 18 | 19 | // The finalizer could be invoked either from check callbacks (as native 20 | // immediates) if the event loop is still running (where napi_ok is returned) 21 | // or during environment shutdown (where napi_cannot_run_js or 22 | // napi_pending_exception is returned). This is not deterministic from 23 | // the point of view of the addon. 24 | 25 | #ifdef NAPI_EXPERIMENTAL 26 | NODE_API_NOGC_ASSERT_RETURN_VOID( 27 | result == napi_cannot_run_js || result == napi_ok, 28 | "getting named property from global in finalizer should succeed " 29 | "or return napi_cannot_run_js"); 30 | #else 31 | NODE_API_NOGC_ASSERT_RETURN_VOID( 32 | result == napi_pending_exception || result == napi_ok, 33 | "getting named property from global in finalizer should succeed " 34 | "or return napi_pending_exception"); 35 | #endif // NAPI_EXPERIMENTAL 36 | free(ref); 37 | } 38 | 39 | static void NogcFinalize(node_api_nogc_env env, void* data, void* hint) { 40 | #ifdef NAPI_EXPERIMENTAL 41 | NODE_API_NOGC_CALL_RETURN_VOID( 42 | env, node_api_post_finalizer(env, Finalize, data, hint)); 43 | #else 44 | Finalize(env, data, hint); 45 | #endif 46 | } 47 | 48 | static napi_value CreateRef(napi_env env, napi_callback_info info) { 49 | size_t argc = 1; 50 | napi_value cb; 51 | napi_valuetype value_type; 52 | napi_ref* ref = malloc(sizeof(*ref)); 53 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &cb, NULL, NULL)); 54 | NODE_API_ASSERT(env, argc == 1, "Function takes only one argument"); 55 | NODE_API_CALL(env, napi_typeof(env, cb, &value_type)); 56 | NODE_API_ASSERT( 57 | env, value_type == napi_function, "argument must be function"); 58 | NODE_API_CALL(env, napi_add_finalizer(env, cb, ref, NogcFinalize, NULL, ref)); 59 | return cb; 60 | } 61 | 62 | EXTERN_C_START 63 | napi_value Init(napi_env env, napi_value exports) { 64 | napi_property_descriptor properties[] = { 65 | DECLARE_NODE_API_PROPERTY("createRef", CreateRef), 66 | }; 67 | 68 | NODE_API_CALL( 69 | env, 70 | napi_define_properties( 71 | env, exports, sizeof(properties) / sizeof(*properties), properties)); 72 | 73 | return exports; 74 | } 75 | EXTERN_C_END 76 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_constructor/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_constructor", 5 | "sources": [ 6 | "test_constructor.c", 7 | "test_null.c", 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_constructor/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | const getterOnlyErrorRE = 6 | /^TypeError: Cannot set property .* of #<.*> which has only a getter$/; 7 | 8 | // Testing api calls for a constructor that defines properties 9 | const TestConstructor = require(`./build/${common.buildType}/test_constructor`); 10 | const test_object = new TestConstructor(); 11 | 12 | assert.strictEqual(test_object.echo('hello'), 'hello'); 13 | 14 | test_object.readwriteValue = 1; 15 | assert.strictEqual(test_object.readwriteValue, 1); 16 | test_object.readwriteValue = 2; 17 | assert.strictEqual(test_object.readwriteValue, 2); 18 | 19 | assert.throws(() => { test_object.readonlyValue = 3; }, 20 | /^TypeError: Cannot assign to read only property 'readonlyValue' of object '#'$/); 21 | 22 | assert.ok(test_object.hiddenValue); 23 | 24 | // Properties with napi_enumerable attribute should be enumerable. 25 | const propertyNames = []; 26 | for (const name in test_object) { 27 | propertyNames.push(name); 28 | } 29 | assert.ok(propertyNames.includes('echo')); 30 | assert.ok(propertyNames.includes('readwriteValue')); 31 | assert.ok(propertyNames.includes('readonlyValue')); 32 | assert.ok(!propertyNames.includes('hiddenValue')); 33 | assert.ok(!propertyNames.includes('readwriteAccessor1')); 34 | assert.ok(!propertyNames.includes('readwriteAccessor2')); 35 | assert.ok(!propertyNames.includes('readonlyAccessor1')); 36 | assert.ok(!propertyNames.includes('readonlyAccessor2')); 37 | 38 | // The napi_writable attribute should be ignored for accessors. 39 | test_object.readwriteAccessor1 = 1; 40 | assert.strictEqual(test_object.readwriteAccessor1, 1); 41 | assert.strictEqual(test_object.readonlyAccessor1, 1); 42 | assert.throws(() => { test_object.readonlyAccessor1 = 3; }, getterOnlyErrorRE); 43 | test_object.readwriteAccessor2 = 2; 44 | assert.strictEqual(test_object.readwriteAccessor2, 2); 45 | assert.strictEqual(test_object.readonlyAccessor2, 2); 46 | assert.throws(() => { test_object.readonlyAccessor2 = 3; }, getterOnlyErrorRE); 47 | 48 | // Validate that static properties are on the class as opposed 49 | // to the instance 50 | assert.strictEqual(TestConstructor.staticReadonlyAccessor1, 10); 51 | assert.strictEqual(test_object.staticReadonlyAccessor1, undefined); 52 | 53 | // Verify that passing NULL to napi_define_class() results in the correct 54 | // error. 55 | assert.deepStrictEqual(TestConstructor.TestDefineClass(), { 56 | envIsNull: 'Invalid argument', 57 | nameIsNull: 'Invalid argument', 58 | cbIsNull: 'Invalid argument', 59 | cbDataIsNull: 'napi_ok', 60 | propertiesIsNull: 'Invalid argument', 61 | resultIsNull: 'Invalid argument', 62 | }); 63 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_constructor/test2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for a constructor that defines properties 6 | const TestConstructor = 7 | require(`./build/${common.buildType}/test_constructor`).constructorName; 8 | assert.strictEqual(TestConstructor.name, 'MyObject'); 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_constructor/test_null.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 2 | #define TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 3 | 4 | #include 5 | 6 | void init_test_null(napi_env env, napi_value exports); 7 | 8 | #endif // TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_constructor/test_null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Test passing NULL to object-related N-APIs. 6 | const { testNull } = require(`./build/${common.buildType}/test_constructor`); 7 | const expectedResult = { 8 | envIsNull: 'Invalid argument', 9 | nameIsNull: 'Invalid argument', 10 | lengthIsZero: 'napi_ok', 11 | nativeSideIsNull: 'Invalid argument', 12 | dataIsNull: 'napi_ok', 13 | propsLengthIsZero: 'napi_ok', 14 | propsIsNull: 'Invalid argument', 15 | resultIsNull: 'Invalid argument', 16 | }; 17 | 18 | assert.deepStrictEqual(testNull.testDefineClass(), expectedResult); 19 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_conversions/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_conversions", 5 | "sources": [ 6 | "test_conversions.c", 7 | "test_null.c", 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_conversions/test_null.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_TEST_CONVERSIONS_TEST_NULL_H_ 2 | #define TEST_JS_NATIVE_API_TEST_CONVERSIONS_TEST_NULL_H_ 3 | 4 | #include 5 | 6 | void init_test_null(napi_env env, napi_value exports); 7 | 8 | #endif // TEST_JS_NATIVE_API_TEST_CONVERSIONS_TEST_NULL_H_ 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_dataview/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_dataview", 5 | "sources": [ 6 | "test_dataview.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_dataview/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for arrays 6 | const test_dataview = require(`./build/${common.buildType}/test_dataview`); 7 | 8 | // Test for creating dataview 9 | { 10 | const buffer = new ArrayBuffer(128); 11 | const template = Reflect.construct(DataView, [buffer]); 12 | 13 | const theDataview = test_dataview.CreateDataViewFromJSDataView(template); 14 | assert.ok(theDataview instanceof DataView, 15 | `Expect ${theDataview} to be a DataView`); 16 | } 17 | 18 | // Test for creating dataview with invalid range 19 | { 20 | const buffer = new ArrayBuffer(128); 21 | assert.throws(() => { 22 | test_dataview.CreateDataView(buffer, 10, 200); 23 | }, RangeError); 24 | } 25 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_date/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_date", 5 | "sources": [ 6 | "test_date.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_date/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common'); 4 | 5 | // This tests the date-related n-api calls 6 | 7 | const assert = require('assert'); 8 | const test_date = require(`./build/${common.buildType}/test_date`); 9 | 10 | const dateTypeTestDate = test_date.createDate(1549183351); 11 | assert.strictEqual(test_date.isDate(dateTypeTestDate), true); 12 | 13 | assert.strictEqual(test_date.isDate(new Date(1549183351)), true); 14 | 15 | assert.strictEqual(test_date.isDate(2.4), false); 16 | assert.strictEqual(test_date.isDate('not a date'), false); 17 | assert.strictEqual(test_date.isDate(undefined), false); 18 | assert.strictEqual(test_date.isDate(null), false); 19 | assert.strictEqual(test_date.isDate({}), false); 20 | 21 | assert.strictEqual(test_date.getDateValue(new Date(1549183351)), 1549183351); 22 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_date/test_date.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value createDate(napi_env env, napi_callback_info info) { 6 | size_t argc = 1; 7 | napi_value args[1]; 8 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 9 | 10 | NODE_API_ASSERT(env, argc >= 1, "Wrong number of arguments"); 11 | 12 | napi_valuetype valuetype0; 13 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0)); 14 | 15 | NODE_API_ASSERT( 16 | env, 17 | valuetype0 == napi_number, 18 | "Wrong type of arguments. Expects a number as first argument."); 19 | 20 | double time; 21 | NODE_API_CALL(env, napi_get_value_double(env, args[0], &time)); 22 | 23 | napi_value date; 24 | NODE_API_CALL(env, napi_create_date(env, time, &date)); 25 | 26 | return date; 27 | } 28 | 29 | static napi_value isDate(napi_env env, napi_callback_info info) { 30 | napi_value date, result; 31 | size_t argc = 1; 32 | bool is_date; 33 | 34 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL)); 35 | NODE_API_CALL(env, napi_is_date(env, date, &is_date)); 36 | NODE_API_CALL(env, napi_get_boolean(env, is_date, &result)); 37 | 38 | return result; 39 | } 40 | 41 | static napi_value getDateValue(napi_env env, napi_callback_info info) { 42 | napi_value date, result; 43 | size_t argc = 1; 44 | double value; 45 | 46 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL)); 47 | NODE_API_CALL(env, napi_get_date_value(env, date, &value)); 48 | NODE_API_CALL(env, napi_create_double(env, value, &result)); 49 | 50 | return result; 51 | } 52 | 53 | EXTERN_C_START 54 | napi_value Init(napi_env env, napi_value exports) { 55 | napi_property_descriptor descriptors[] = { 56 | DECLARE_NODE_API_PROPERTY("createDate", createDate), 57 | DECLARE_NODE_API_PROPERTY("isDate", isDate), 58 | DECLARE_NODE_API_PROPERTY("getDateValue", getDateValue), 59 | }; 60 | 61 | NODE_API_CALL( 62 | env, 63 | napi_define_properties(env, 64 | exports, 65 | sizeof(descriptors) / sizeof(*descriptors), 66 | descriptors)); 67 | 68 | return exports; 69 | } 70 | EXTERN_C_END 71 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_error/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_error", 5 | "sources": [ 6 | "test_error.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_exception/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_exception", 5 | "sources": [ 6 | "test_exception.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_exception/testFinalizerException.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | if (process.argv[2] === 'child') { 3 | const common = require('../../common'); 4 | // Trying, catching the exception, and finding the bindings at the `Error`'s 5 | // `binding` property is done intentionally, because we're also testing what 6 | // happens when the add-on entry point throws. See test.js. 7 | try { 8 | require(`./build/${common.buildType}/test_exception`); 9 | } catch (anException) { 10 | anException.binding.createExternal(); 11 | } 12 | 13 | // Collect garbage 10 times. At least one of those should throw the exception 14 | // and cause the whole process to bail with it, its text printed to stderr and 15 | // asserted by the parent process to match expectations. 16 | let gcCount = 10; 17 | (function gcLoop() { 18 | global.gc(); 19 | if (--gcCount > 0) { 20 | setImmediate(() => gcLoop()); 21 | } 22 | })(); 23 | return; 24 | } 25 | 26 | const assert = require('assert'); 27 | const { spawnSync } = require('child_process'); 28 | const child = spawnSync(process.execPath, [ 29 | '--expose-gc', __filename, 'child', 30 | ]); 31 | assert.strictEqual(child.signal, null); 32 | assert.match(child.stderr.toString(), /Error during Finalize/); 33 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_finalizer/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_finalizer", 5 | "defines": [ "NAPI_EXPERIMENTAL" ], 6 | "sources": [ 7 | "test_finalizer.c" 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_finalizer/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const test_finalizer = require(`./build/${common.buildType}/test_finalizer`); 6 | const assert = require('assert'); 7 | 8 | // The goal of this test is to show that we can run "pure" finalizers in the 9 | // current JS loop tick. Thus, we do not use common.gcUntil function works 10 | // asynchronously using micro tasks. 11 | // We use IIFE for the obj scope instead of {} to be compatible with 12 | // non-V8 JS engines that do not support scoped variables. 13 | (() => { 14 | const obj = {}; 15 | test_finalizer.addFinalizer(obj); 16 | })(); 17 | 18 | for (let i = 0; i < 10; ++i) { 19 | global.gc(); 20 | if (test_finalizer.getFinalizerCallCount() === 1) { 21 | break; 22 | } 23 | } 24 | 25 | assert.strictEqual(test_finalizer.getFinalizerCallCount(), 1); 26 | 27 | // The finalizer that access JS cannot run synchronously. They are run in the 28 | // next JS loop tick. Thus, we must use common.gcUntil. 29 | async function runAsyncTests() { 30 | // We do not use common.mustCall() because we want to see the finalizer 31 | // called in response to GC and not as a part of env destruction. 32 | let js_is_called = false; 33 | // We use IIFE for the obj scope instead of {} to be compatible with 34 | // non-V8 JS engines that do not support scoped variables. 35 | (() => { 36 | const obj = {}; 37 | test_finalizer.addFinalizerWithJS(obj, () => { js_is_called = true; }); 38 | })(); 39 | await common.gcUntil('ensure JS finalizer called', 40 | () => (test_finalizer.getFinalizerCallCount() === 2)); 41 | assert(js_is_called); 42 | } 43 | runAsyncTests(); 44 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_finalizer/test_fatal_finalize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | 4 | if (process.argv[2] === 'child') { 5 | const test_finalizer = require(`./build/${common.buildType}/test_finalizer`); 6 | 7 | (() => { 8 | const obj = {}; 9 | test_finalizer.addFinalizerFailOnJS(obj); 10 | })(); 11 | 12 | // Collect garbage 10 times. At least one of those should throw the exception 13 | // and cause the whole process to bail with it, its text printed to stderr and 14 | // asserted by the parent process to match expectations. 15 | let gcCount = 10; 16 | (function gcLoop() { 17 | global.gc(); 18 | if (--gcCount > 0) { 19 | setImmediate(() => gcLoop()); 20 | } 21 | })(); 22 | return; 23 | } 24 | 25 | const assert = require('assert'); 26 | const { spawnSync } = require('child_process'); 27 | const child = spawnSync(process.execPath, [ 28 | '--expose-gc', __filename, 'child', 29 | ]); 30 | assert(common.nodeProcessAborted(child.status, child.signal)); 31 | assert.match(child.stderr.toString(), /Finalizer is calling a function that may affect GC state/); 32 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_function/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_function", 5 | "sources": [ 6 | "test_function.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_function/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const assert = require('assert'); 6 | 7 | // Testing api calls for function 8 | const test_function = require(`./build/${common.buildType}/test_function`); 9 | 10 | function func1() { 11 | return 1; 12 | } 13 | assert.strictEqual(test_function.TestCall(func1), 1); 14 | 15 | function func2() { 16 | console.log('hello world!'); 17 | return null; 18 | } 19 | assert.strictEqual(test_function.TestCall(func2), null); 20 | 21 | function func3(input) { 22 | return input + 1; 23 | } 24 | assert.strictEqual(test_function.TestCall(func3, 1), 2); 25 | 26 | function func4(input) { 27 | return func3(input); 28 | } 29 | assert.strictEqual(test_function.TestCall(func4, 1), 2); 30 | 31 | assert.strictEqual(test_function.TestName.name, 'Name'); 32 | assert.strictEqual(test_function.TestNameShort.name, 'Name_'); 33 | 34 | let tracked_function = test_function.MakeTrackedFunction(common.mustCall()); 35 | assert(!!tracked_function); 36 | tracked_function = null; 37 | global.gc(); 38 | 39 | assert.deepStrictEqual(test_function.TestCreateFunctionParameters(), { 40 | envIsNull: 'Invalid argument', 41 | nameIsNull: 'napi_ok', 42 | cbIsNull: 'Invalid argument', 43 | resultIsNull: 'Invalid argument', 44 | }); 45 | 46 | assert.throws( 47 | () => test_function.TestBadReturnExceptionPending(), 48 | { 49 | code: 'throwing exception', 50 | name: 'Error', 51 | }, 52 | ); 53 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_general", 5 | "sources": [ 6 | "test_general.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const test_general = require(`./build/${common.buildType}/test_general`); 6 | const assert = require('assert'); 7 | 8 | const val1 = '1'; 9 | const val2 = 1; 10 | const val3 = 1; 11 | 12 | class BaseClass { 13 | } 14 | 15 | class ExtendedClass extends BaseClass { 16 | } 17 | 18 | const baseObject = new BaseClass(); 19 | const extendedObject = new ExtendedClass(); 20 | 21 | // Test napi_strict_equals 22 | assert.ok(test_general.testStrictEquals(val1, val1)); 23 | assert.strictEqual(test_general.testStrictEquals(val1, val2), false); 24 | assert.ok(test_general.testStrictEquals(val2, val3)); 25 | 26 | // Test napi_get_prototype 27 | assert.strictEqual(test_general.testGetPrototype(baseObject), 28 | Object.getPrototypeOf(baseObject)); 29 | assert.strictEqual(test_general.testGetPrototype(extendedObject), 30 | Object.getPrototypeOf(extendedObject)); 31 | // Prototypes for base and extended should be different. 32 | assert.notStrictEqual(test_general.testGetPrototype(baseObject), 33 | test_general.testGetPrototype(extendedObject)); 34 | 35 | // Test version management functions 36 | assert.strictEqual(test_general.testGetVersion(), 9); 37 | 38 | [ 39 | 123, 40 | 'test string', 41 | function() {}, 42 | new Object(), 43 | true, 44 | undefined, 45 | Symbol(), 46 | ].forEach((val) => { 47 | assert.strictEqual(test_general.testNapiTypeof(val), typeof val); 48 | }); 49 | 50 | // Since typeof in js return object need to validate specific case 51 | // for null 52 | assert.strictEqual(test_general.testNapiTypeof(null), 'null'); 53 | 54 | // Assert that wrapping twice fails. 55 | const x = {}; 56 | test_general.wrap(x); 57 | assert.throws(() => test_general.wrap(x), 58 | { name: 'Error', message: 'Invalid argument' }); 59 | // Clean up here, otherwise derefItemWasCalled() will be polluted. 60 | test_general.removeWrap(x); 61 | 62 | // Ensure that wrapping, removing the wrap, and then wrapping again works. 63 | const y = {}; 64 | test_general.wrap(y); 65 | test_general.removeWrap(y); 66 | // Wrapping twice succeeds if a remove_wrap() separates the instances 67 | test_general.wrap(y); 68 | // Clean up here, otherwise derefItemWasCalled() will be polluted. 69 | test_general.removeWrap(y); 70 | 71 | // Test napi_adjust_external_memory 72 | const adjustedValue = test_general.testAdjustExternalMemory(); 73 | assert.strictEqual(typeof adjustedValue, 'number'); 74 | assert(adjustedValue > 0); 75 | 76 | async function runGCTests() { 77 | // Ensure that garbage collecting an object with a wrapped native item results 78 | // in the finalize callback being called. 79 | assert.strictEqual(test_general.derefItemWasCalled(), false); 80 | 81 | (() => test_general.wrap({}))(); 82 | await common.gcUntil('deref_item() was called upon garbage collecting a ' + 83 | 'wrapped object.', 84 | () => test_general.derefItemWasCalled()); 85 | 86 | // Ensure that removing a wrap and garbage collecting does not fire the 87 | // finalize callback. 88 | let z = {}; 89 | test_general.testFinalizeWrap(z); 90 | test_general.removeWrap(z); 91 | z = null; 92 | await common.gcUntil( 93 | 'finalize callback was not called upon garbage collection.', 94 | () => (!test_general.finalizeWasCalled())); 95 | } 96 | runGCTests(); 97 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testEnvCleanup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (process.argv[2] === 'child') { 4 | const common = require('../../common'); 5 | const test_general = require(`./build/${common.buildType}/test_general`); 6 | 7 | // The second argument to `envCleanupWrap()` is an index into the global 8 | // static string array named `env_cleanup_finalizer_messages` on the native 9 | // side. A reverse mapping is reproduced here for clarity. 10 | const finalizerMessages = { 11 | 'simple wrap': 0, 12 | 'wrap, removeWrap': 1, 13 | 'first wrap': 2, 14 | 'second wrap': 3, 15 | }; 16 | 17 | // We attach the three objects we will test to `module.exports` to ensure they 18 | // will not be garbage-collected before the process exits. 19 | 20 | // Make sure the finalizer for a simple wrap will be called at env cleanup. 21 | module.exports['simple wrap'] = 22 | test_general.envCleanupWrap({}, finalizerMessages['simple wrap']); 23 | 24 | // Make sure that a removed wrap does not result in a call to its finalizer at 25 | // env cleanup. 26 | module.exports['wrap, removeWrap'] = 27 | test_general.envCleanupWrap({}, finalizerMessages['wrap, removeWrap']); 28 | test_general.removeWrap(module.exports['wrap, removeWrap']); 29 | 30 | // Make sure that only the latest attached version of a re-wrapped item's 31 | // finalizer gets called at env cleanup. 32 | module.exports['first wrap'] = 33 | test_general.envCleanupWrap({}, finalizerMessages['first wrap']); 34 | test_general.removeWrap(module.exports['first wrap']); 35 | test_general.envCleanupWrap(module.exports['first wrap'], 36 | finalizerMessages['second wrap']); 37 | } else { 38 | const assert = require('assert'); 39 | const { spawnSync } = require('child_process'); 40 | 41 | const child = spawnSync(process.execPath, [__filename, 'child'], { 42 | stdio: [ process.stdin, 'pipe', process.stderr ], 43 | }); 44 | 45 | // Grab the child's output and construct an object whose keys are the rows of 46 | // the output and whose values are `true`, so we can compare the output while 47 | // ignoring the order in which the lines of it were produced. 48 | assert.deepStrictEqual( 49 | child.stdout.toString().split(/\r\n|\r|\n/g).reduce((obj, item) => 50 | Object.assign(obj, item ? { [item]: true } : {}), {}), { 51 | 'finalize at env cleanup for simple wrap': true, 52 | 'finalize at env cleanup for second wrap': true, 53 | }); 54 | 55 | // Ensure that the child exited successfully. 56 | assert.strictEqual(child.status, 0); 57 | } 58 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testFinalizer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Flags: --expose-gc 3 | 4 | const common = require('../../common'); 5 | const test_general = require(`./build/${common.buildType}/test_general`); 6 | const assert = require('assert'); 7 | 8 | let finalized = {}; 9 | const callback = common.mustCall(2); 10 | 11 | // Add two items to be finalized and ensure the callback is called for each. 12 | test_general.addFinalizerOnly(finalized, callback); 13 | test_general.addFinalizerOnly(finalized, callback); 14 | 15 | // Ensure attached items cannot be retrieved. 16 | assert.throws(() => test_general.unwrap(finalized), 17 | { name: 'Error', message: 'Invalid argument' }); 18 | 19 | // Ensure attached items cannot be removed. 20 | assert.throws(() => test_general.removeWrap(finalized), 21 | { name: 'Error', message: 'Invalid argument' }); 22 | finalized = null; 23 | global.gc(); 24 | 25 | // Add an item to an object that is already wrapped, and ensure that its 26 | // finalizer as well as the wrap finalizer gets called. 27 | async function testFinalizeAndWrap() { 28 | assert.strictEqual(test_general.derefItemWasCalled(), false); 29 | let finalizeAndWrap = {}; 30 | test_general.wrap(finalizeAndWrap); 31 | test_general.addFinalizerOnly(finalizeAndWrap, common.mustCall()); 32 | finalizeAndWrap = null; 33 | await common.gcUntil('test finalize and wrap', 34 | () => test_general.derefItemWasCalled()); 35 | } 36 | testFinalizeAndWrap(); 37 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testGlobals.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | const test_globals = require(`./build/${common.buildType}/test_general`); 6 | 7 | assert.strictEqual(test_globals.getUndefined(), undefined); 8 | assert.strictEqual(test_globals.getNull(), null); 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testInstanceOf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | //const fs = require('fs'); 4 | const assert = require('assert'); 5 | 6 | // Addon is referenced through the eval expression in testFile 7 | const addon = require(`./build/${common.buildType}/test_general`); 8 | // const path = require('path'); 9 | 10 | // // This test depends on a number of V8 tests. 11 | // const v8TestsDir = path.resolve(__dirname, '..', '..', '..', 'deps', 'v8', 12 | // 'test', 'mjsunit'); 13 | // const v8TestsDirExists = fs.existsSync(v8TestsDir); 14 | 15 | // // The following assert functions are referenced by v8's unit tests 16 | // // See for instance deps/v8/test/mjsunit/instanceof.js 17 | // // eslint-disable-next-line no-unused-vars 18 | // function assertTrue(assertion) { 19 | // return assert.strictEqual(assertion, true); 20 | // } 21 | 22 | // // eslint-disable-next-line no-unused-vars 23 | // function assertFalse(assertion) { 24 | // assert.strictEqual(assertion, false); 25 | // } 26 | 27 | // // eslint-disable-next-line no-unused-vars 28 | // function assertEquals(leftHandSide, rightHandSide) { 29 | // assert.strictEqual(leftHandSide, rightHandSide); 30 | // } 31 | 32 | // // eslint-disable-next-line no-unused-vars 33 | // function assertThrows(statement) { 34 | // assert.throws(function() { 35 | // eval(statement); 36 | // }, Error); 37 | // } 38 | 39 | // function testFile(fileName) { 40 | // try { 41 | // const contents = fs.readFileSync(fileName, { encoding: 'utf8' }); 42 | // eval(contents.replace(/[(]([^\s(]+)\s+instanceof\s+([^)]+)[)]/g, 43 | // '(addon.doInstanceOf($1, $2))')); 44 | // } catch (err) { 45 | // // This test depends on V8 test files, which may not exist in downloaded 46 | // // archives. Emit a warning if the tests cannot be found instead of failing. 47 | // if (err.code === 'ENOENT' && !v8TestsDirExists) 48 | // process.emitWarning(`test file ${fileName} does not exist.`); 49 | // else 50 | // throw err; 51 | // } 52 | // } 53 | 54 | // testFile(path.join(v8TestsDir, 'instanceof.js')); 55 | // testFile(path.join(v8TestsDir, 'instanceof-2.js')); 56 | 57 | // We can only perform this test if we have a working Symbol.hasInstance 58 | if (typeof Symbol !== 'undefined' && 'hasInstance' in Symbol && 59 | typeof Symbol.hasInstance === 'symbol') { 60 | 61 | function compareToNative(theObject, theConstructor) { 62 | assert.strictEqual( 63 | addon.doInstanceOf(theObject, theConstructor), 64 | (theObject instanceof theConstructor), 65 | ); 66 | } 67 | 68 | function MyClass() {} 69 | Object.defineProperty(MyClass, Symbol.hasInstance, { 70 | value: function(candidate) { 71 | return 'mark' in candidate; 72 | }, 73 | }); 74 | 75 | function MySubClass() {} 76 | MySubClass.prototype = new MyClass(); 77 | 78 | let x = new MySubClass(); 79 | let y = new MySubClass(); 80 | x.mark = true; 81 | 82 | compareToNative(x, MySubClass); 83 | compareToNative(y, MySubClass); 84 | compareToNative(x, MyClass); 85 | compareToNative(y, MyClass); 86 | 87 | x = new MyClass(); 88 | y = new MyClass(); 89 | x.mark = true; 90 | 91 | compareToNative(x, MySubClass); 92 | compareToNative(y, MySubClass); 93 | compareToNative(x, MyClass); 94 | compareToNative(y, MyClass); 95 | } 96 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testNapiRun.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common'); 4 | const assert = require('assert'); 5 | 6 | // `addon` is referenced through the eval expression in testFile 7 | const addon = require(`./build/${common.buildType}/test_general`); 8 | 9 | const testCase = '(41.92 + 0.08);'; 10 | const expected = 42; 11 | const actual = addon.testNapiRun(testCase); 12 | 13 | assert.strictEqual(actual, expected); 14 | assert.throws(() => addon.testNapiRun({ abc: 'def' }), /string was expected/); 15 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_general/testNapiStatus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common'); 4 | const addon = require(`./build/${common.buildType}/test_general`); 5 | const assert = require('assert'); 6 | 7 | addon.createNapiError(); 8 | assert(addon.testNapiErrorCleanup(), 'napi_status cleaned up for second call'); 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_handle_scope/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_handle_scope", 5 | "sources": [ 6 | "test_handle_scope.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_handle_scope/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing handle scope api calls 6 | const testHandleScope = 7 | require(`./build/${common.buildType}/test_handle_scope`); 8 | 9 | testHandleScope.NewScope(); 10 | 11 | assert.ok(testHandleScope.NewScopeEscape() instanceof Object); 12 | 13 | testHandleScope.NewScopeEscapeTwice(); 14 | 15 | assert.throws( 16 | () => { 17 | testHandleScope.NewScopeWithException(() => { throw new RangeError(); }); 18 | }, 19 | RangeError); 20 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_handle_scope/test_handle_scope.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../common.h" 4 | #include "../entry_point.h" 5 | 6 | // these tests validate the handle scope functions in the normal 7 | // flow. Forcing gc behavior to fully validate they are doing 8 | // the right right thing would be quite hard so we keep it 9 | // simple for now. 10 | 11 | static napi_value NewScope(napi_env env, napi_callback_info info) { 12 | napi_handle_scope scope; 13 | napi_value output = NULL; 14 | 15 | NODE_API_CALL(env, napi_open_handle_scope(env, &scope)); 16 | NODE_API_CALL(env, napi_create_object(env, &output)); 17 | NODE_API_CALL(env, napi_close_handle_scope(env, scope)); 18 | return NULL; 19 | } 20 | 21 | static napi_value NewScopeEscape(napi_env env, napi_callback_info info) { 22 | napi_escapable_handle_scope scope; 23 | napi_value output = NULL; 24 | napi_value escapee = NULL; 25 | 26 | NODE_API_CALL(env, napi_open_escapable_handle_scope(env, &scope)); 27 | NODE_API_CALL(env, napi_create_object(env, &output)); 28 | NODE_API_CALL(env, napi_escape_handle(env, scope, output, &escapee)); 29 | NODE_API_CALL(env, napi_close_escapable_handle_scope(env, scope)); 30 | return escapee; 31 | } 32 | 33 | static napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { 34 | napi_escapable_handle_scope scope; 35 | napi_value output = NULL; 36 | napi_value escapee = NULL; 37 | napi_status status; 38 | 39 | NODE_API_CALL(env, napi_open_escapable_handle_scope(env, &scope)); 40 | NODE_API_CALL(env, napi_create_object(env, &output)); 41 | NODE_API_CALL(env, napi_escape_handle(env, scope, output, &escapee)); 42 | status = napi_escape_handle(env, scope, output, &escapee); 43 | NODE_API_ASSERT( 44 | env, status == napi_escape_called_twice, "Escaping twice fails"); 45 | NODE_API_CALL(env, napi_close_escapable_handle_scope(env, scope)); 46 | return NULL; 47 | } 48 | 49 | static napi_value NewScopeWithException(napi_env env, napi_callback_info info) { 50 | napi_handle_scope scope; 51 | size_t argc; 52 | napi_value exception_function; 53 | napi_status status; 54 | napi_value output = NULL; 55 | 56 | NODE_API_CALL(env, napi_open_handle_scope(env, &scope)); 57 | NODE_API_CALL(env, napi_create_object(env, &output)); 58 | 59 | argc = 1; 60 | NODE_API_CALL( 61 | env, napi_get_cb_info(env, info, &argc, &exception_function, NULL, NULL)); 62 | 63 | status = napi_call_function(env, output, exception_function, 0, NULL, NULL); 64 | NODE_API_ASSERT( 65 | env, status == napi_pending_exception, "Function should have thrown."); 66 | 67 | // Closing a handle scope should still work while an exception is pending. 68 | NODE_API_CALL(env, napi_close_handle_scope(env, scope)); 69 | return NULL; 70 | } 71 | 72 | EXTERN_C_START 73 | napi_value Init(napi_env env, napi_value exports) { 74 | napi_property_descriptor properties[] = { 75 | DECLARE_NODE_API_PROPERTY("NewScope", NewScope), 76 | DECLARE_NODE_API_PROPERTY("NewScopeEscape", NewScopeEscape), 77 | DECLARE_NODE_API_PROPERTY("NewScopeEscapeTwice", NewScopeEscapeTwice), 78 | DECLARE_NODE_API_PROPERTY("NewScopeWithException", NewScopeWithException), 79 | }; 80 | 81 | NODE_API_CALL( 82 | env, 83 | napi_define_properties( 84 | env, exports, sizeof(properties) / sizeof(*properties), properties)); 85 | 86 | return exports; 87 | } 88 | EXTERN_C_END 89 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_instance_data/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_instance_data", 5 | "sources": [ 6 | "test_instance_data.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_instance_data/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Test API calls for instance data. 3 | 4 | const common = require('../../common'); 5 | const assert = require('assert'); 6 | 7 | if (module !== require.main) { 8 | // When required as a module, run the tests. 9 | const test_instance_data = 10 | require(`./build/${common.buildType}/test_instance_data`); 11 | 12 | // Print to stdout when the environment deletes the instance data. This output 13 | // is checked by the parent process. 14 | test_instance_data.setPrintOnDelete(); 15 | 16 | // Test that instance data can be accessed from a binding. 17 | assert.strictEqual(test_instance_data.increment(), 42); 18 | 19 | // Test that the instance data can be accessed from a finalizer. 20 | test_instance_data.objectWithFinalizer(common.mustCall()); 21 | global.gc(); 22 | } else { 23 | // When launched as a script, run tests in either a child process or in a 24 | // worker thread. 25 | const requireAs = require('../../common/require-as'); 26 | const runOptions = { stdio: ['inherit', 'pipe', 'inherit'] }; 27 | 28 | function checkOutput(child) { 29 | assert.strictEqual(child.status, 0); 30 | assert.strictEqual( 31 | (child.stdout.toString().split(/\r\n?|\n/) || [])[0], 32 | 'deleting addon data'); 33 | } 34 | 35 | // Run tests in a child process. 36 | checkOutput(requireAs(__filename, ['--expose-gc'], runOptions, 'child')); 37 | 38 | // Run tests in a worker thread in a child process. 39 | checkOutput(requireAs(__filename, ['--expose-gc'], runOptions, 'worker')); 40 | } 41 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_instance_data/test_instance_data.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../common.h" 5 | #include "../entry_point.h" 6 | 7 | typedef struct { 8 | size_t value; 9 | bool print; 10 | napi_ref js_cb_ref; 11 | } AddonData; 12 | 13 | static napi_value Increment(napi_env env, napi_callback_info info) { 14 | AddonData* data; 15 | napi_value result; 16 | 17 | NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 18 | NODE_API_CALL(env, napi_create_uint32(env, ++data->value, &result)); 19 | 20 | return result; 21 | } 22 | 23 | static void DeleteAddonData(napi_env env, void* raw_data, void* hint) { 24 | AddonData* data = raw_data; 25 | if (data->print) { 26 | printf("deleting addon data\n"); 27 | } 28 | if (data->js_cb_ref != NULL) { 29 | NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, data->js_cb_ref)); 30 | } 31 | free(data); 32 | } 33 | 34 | static napi_value SetPrintOnDelete(napi_env env, napi_callback_info info) { 35 | AddonData* data; 36 | 37 | NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 38 | data->print = true; 39 | 40 | return NULL; 41 | } 42 | 43 | static void TestFinalizer(napi_env env, void* raw_data, void* hint) { 44 | (void)raw_data; 45 | (void)hint; 46 | 47 | AddonData* data; 48 | NODE_API_CALL_RETURN_VOID(env, napi_get_instance_data(env, (void**)&data)); 49 | napi_value js_cb, undefined; 50 | NODE_API_CALL_RETURN_VOID( 51 | env, napi_get_reference_value(env, data->js_cb_ref, &js_cb)); 52 | NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); 53 | NODE_API_CALL_RETURN_VOID( 54 | env, napi_call_function(env, undefined, js_cb, 0, NULL, NULL)); 55 | NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, data->js_cb_ref)); 56 | data->js_cb_ref = NULL; 57 | } 58 | 59 | static napi_value ObjectWithFinalizer(napi_env env, napi_callback_info info) { 60 | AddonData* data; 61 | napi_value result, js_cb; 62 | size_t argc = 1; 63 | 64 | NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 65 | NODE_API_ASSERT(env, data->js_cb_ref == NULL, "reference must be NULL"); 66 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &js_cb, NULL, NULL)); 67 | NODE_API_CALL(env, napi_create_object(env, &result)); 68 | NODE_API_CALL( 69 | env, napi_add_finalizer(env, result, NULL, TestFinalizer, NULL, NULL)); 70 | NODE_API_CALL(env, napi_create_reference(env, js_cb, 1, &data->js_cb_ref)); 71 | 72 | return result; 73 | } 74 | 75 | EXTERN_C_START 76 | napi_value Init(napi_env env, napi_value exports) { 77 | AddonData* data = malloc(sizeof(*data)); 78 | data->value = 41; 79 | data->print = false; 80 | data->js_cb_ref = NULL; 81 | 82 | NODE_API_CALL(env, napi_set_instance_data(env, data, DeleteAddonData, NULL)); 83 | 84 | napi_property_descriptor props[] = { 85 | DECLARE_NODE_API_PROPERTY("increment", Increment), 86 | DECLARE_NODE_API_PROPERTY("setPrintOnDelete", SetPrintOnDelete), 87 | DECLARE_NODE_API_PROPERTY("objectWithFinalizer", ObjectWithFinalizer), 88 | }; 89 | 90 | NODE_API_CALL(env, 91 | napi_define_properties( 92 | env, exports, sizeof(props) / sizeof(*props), props)); 93 | 94 | return exports; 95 | } 96 | EXTERN_C_END 97 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_new_target/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'test_new_target', 5 | 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 6 | 'sources': [ 7 | 'test_new_target.c' 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_new_target/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common'); 4 | const assert = require('assert'); 5 | const binding = require(`./build/${common.buildType}/test_new_target`); 6 | 7 | class Class extends binding.BaseClass { 8 | constructor() { 9 | super(); 10 | this.method(); 11 | } 12 | method() { 13 | this.ok = true; 14 | } 15 | } 16 | 17 | assert.ok(new Class() instanceof binding.BaseClass); 18 | assert.ok(new Class().ok); 19 | assert.ok(binding.OrdinaryFunction()); 20 | assert.ok( 21 | new binding.Constructor(binding.Constructor) instanceof binding.Constructor); 22 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_new_target/test_new_target.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value BaseClass(napi_env env, napi_callback_info info) { 6 | napi_value newTargetArg; 7 | NODE_API_CALL(env, napi_get_new_target(env, info, &newTargetArg)); 8 | napi_value thisArg; 9 | NODE_API_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL)); 10 | napi_value undefined; 11 | NODE_API_CALL(env, napi_get_undefined(env, &undefined)); 12 | 13 | // this !== new.target since we are being invoked through super() 14 | bool result; 15 | NODE_API_CALL(env, napi_strict_equals(env, newTargetArg, thisArg, &result)); 16 | NODE_API_ASSERT(env, !result, "this !== new.target"); 17 | 18 | // new.target !== undefined because we should be called as a new expression 19 | NODE_API_ASSERT(env, newTargetArg != NULL, "newTargetArg != NULL"); 20 | NODE_API_CALL(env, napi_strict_equals(env, newTargetArg, undefined, &result)); 21 | NODE_API_ASSERT(env, !result, "new.target !== undefined"); 22 | 23 | return thisArg; 24 | } 25 | 26 | static napi_value Constructor(napi_env env, napi_callback_info info) { 27 | bool result; 28 | napi_value newTargetArg; 29 | NODE_API_CALL(env, napi_get_new_target(env, info, &newTargetArg)); 30 | size_t argc = 1; 31 | napi_value argv; 32 | napi_value thisArg; 33 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisArg, NULL)); 34 | napi_value undefined; 35 | NODE_API_CALL(env, napi_get_undefined(env, &undefined)); 36 | 37 | // new.target !== undefined because we should be called as a new expression 38 | NODE_API_ASSERT(env, newTargetArg != NULL, "newTargetArg != NULL"); 39 | NODE_API_CALL(env, napi_strict_equals(env, newTargetArg, undefined, &result)); 40 | NODE_API_ASSERT(env, !result, "new.target !== undefined"); 41 | 42 | // arguments[0] should be Constructor itself (test harness passed it) 43 | NODE_API_CALL(env, napi_strict_equals(env, newTargetArg, argv, &result)); 44 | NODE_API_ASSERT(env, result, "new.target === Constructor"); 45 | 46 | return thisArg; 47 | } 48 | 49 | static napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { 50 | napi_value newTargetArg; 51 | NODE_API_CALL(env, napi_get_new_target(env, info, &newTargetArg)); 52 | 53 | NODE_API_ASSERT(env, newTargetArg == NULL, "newTargetArg == NULL"); 54 | 55 | napi_value _true; 56 | NODE_API_CALL(env, napi_get_boolean(env, true, &_true)); 57 | return _true; 58 | } 59 | 60 | EXTERN_C_START 61 | napi_value Init(napi_env env, napi_value exports) { 62 | const napi_property_descriptor desc[] = { 63 | DECLARE_NODE_API_PROPERTY("BaseClass", BaseClass), 64 | DECLARE_NODE_API_PROPERTY("OrdinaryFunction", OrdinaryFunction), 65 | DECLARE_NODE_API_PROPERTY("Constructor", Constructor)}; 66 | NODE_API_CALL(env, napi_define_properties(env, exports, 3, desc)); 67 | return exports; 68 | } 69 | EXTERN_C_END 70 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_number/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_number", 5 | "sources": [ 6 | "test_number.c", 7 | "test_null.c", 8 | ] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_number/test_null.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_TEST_NUMBER_TEST_NULL_H_ 2 | #define TEST_JS_NATIVE_API_TEST_NUMBER_TEST_NULL_H_ 3 | 4 | #include 5 | 6 | void init_test_null(napi_env env, napi_value exports); 7 | 8 | #endif // TEST_JS_NATIVE_API_TEST_NUMBER_TEST_NULL_H_ 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_number/test_null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const { testNull } = require(`./build/${common.buildType}/test_number`); 5 | 6 | const expectedCreateResult = { 7 | envIsNull: 'Invalid argument', 8 | resultIsNull: 'Invalid argument', 9 | }; 10 | const expectedGetValueResult = { 11 | envIsNull: 'Invalid argument', 12 | resultIsNull: 'Invalid argument', 13 | valueIsNull: 'Invalid argument', 14 | }; 15 | [ 'Double', 'Int32', 'Uint32', 'Int64' ].forEach((typeName) => { 16 | assert.deepStrictEqual(testNull['create' + typeName](), expectedCreateResult); 17 | assert.deepStrictEqual(testNull['getValue' + typeName](), expectedGetValueResult); 18 | }); 19 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_object/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_object", 5 | "sources": [ 6 | "test_null.c", 7 | "test_object.c" 8 | ] 9 | }, 10 | { 11 | "target_name": "test_exceptions", 12 | "sources": [ 13 | "test_exceptions.c", 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_object/test_exceptions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../common.h" 5 | #include "../entry_point.h" 6 | 7 | static napi_value TestExceptions(napi_env env, napi_callback_info info) { 8 | size_t argc = 1; 9 | napi_value args[1]; 10 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 11 | 12 | napi_value target = args[0]; 13 | napi_value exception, key, value; 14 | napi_status status; 15 | bool is_exception_pending; 16 | bool bool_result; 17 | 18 | NODE_API_CALL(env, 19 | napi_create_string_utf8(env, "key", NAPI_AUTO_LENGTH, &key)); 20 | NODE_API_CALL( 21 | env, napi_create_string_utf8(env, "value", NAPI_AUTO_LENGTH, &value)); 22 | 23 | #define PROCEDURE(call) \ 24 | { \ 25 | status = (call); \ 26 | NODE_API_ASSERT( \ 27 | env, status == napi_pending_exception, "expect exception pending"); \ 28 | NODE_API_CALL(env, napi_is_exception_pending(env, &is_exception_pending)); \ 29 | NODE_API_ASSERT(env, is_exception_pending, "expect exception pending"); \ 30 | NODE_API_CALL(env, napi_get_and_clear_last_exception(env, &exception)); \ 31 | } 32 | // discard the exception values. 33 | 34 | // properties 35 | PROCEDURE(napi_set_property(env, target, key, value)); 36 | PROCEDURE(napi_set_named_property(env, target, "key", value)); 37 | PROCEDURE(napi_has_property(env, target, key, &bool_result)); 38 | PROCEDURE(napi_has_own_property(env, target, key, &bool_result)); 39 | PROCEDURE(napi_has_named_property(env, target, "key", &bool_result)); 40 | PROCEDURE(napi_get_property(env, target, key, &value)); 41 | PROCEDURE(napi_get_named_property(env, target, "key", &value)); 42 | PROCEDURE(napi_delete_property(env, target, key, &bool_result)); 43 | 44 | // elements 45 | PROCEDURE(napi_set_element(env, target, 0, value)); 46 | PROCEDURE(napi_has_element(env, target, 0, &bool_result)); 47 | PROCEDURE(napi_get_element(env, target, 0, &value)); 48 | PROCEDURE(napi_delete_element(env, target, 0, &bool_result)); 49 | 50 | napi_property_descriptor descriptors[] = { 51 | DECLARE_NODE_API_PROPERTY_VALUE("key", value), 52 | }; 53 | PROCEDURE(napi_define_properties( 54 | env, target, sizeof(descriptors) / sizeof(*descriptors), descriptors)); 55 | 56 | PROCEDURE(napi_get_all_property_names(env, 57 | target, 58 | napi_key_own_only, 59 | napi_key_enumerable, 60 | napi_key_keep_numbers, 61 | &value)); 62 | PROCEDURE(napi_get_property_names(env, target, &value)); 63 | 64 | return NULL; 65 | } 66 | 67 | EXTERN_C_START 68 | napi_value Init(napi_env env, napi_value exports) { 69 | napi_property_descriptor descriptors[] = { 70 | DECLARE_NODE_API_PROPERTY("testExceptions", TestExceptions), 71 | }; 72 | 73 | NODE_API_CALL( 74 | env, 75 | napi_define_properties(env, 76 | exports, 77 | sizeof(descriptors) / sizeof(*descriptors), 78 | descriptors)); 79 | 80 | return exports; 81 | } 82 | EXTERN_C_END 83 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_object/test_exceptions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | 4 | // Test 5 | const { testExceptions } = require(`./build/${common.buildType}/test_exceptions`); 6 | 7 | function throws() { 8 | throw new Error('foobar'); 9 | } 10 | testExceptions(new Proxy({}, { 11 | get: common.mustCallAtLeast(throws, 1), 12 | getOwnPropertyDescriptor: common.mustCallAtLeast(throws, 1), 13 | defineProperty: common.mustCallAtLeast(throws, 1), 14 | deleteProperty: common.mustCallAtLeast(throws, 1), 15 | has: common.mustCallAtLeast(throws, 1), 16 | set: common.mustCallAtLeast(throws, 1), 17 | ownKeys: common.mustCallAtLeast(throws, 1), 18 | })); 19 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_object/test_null.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 2 | #define TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 3 | 4 | #include 5 | 6 | void init_test_null(napi_env env, napi_value exports); 7 | 8 | #endif // TEST_JS_NATIVE_API_TEST_OBJECT_TEST_NULL_H_ 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_object/test_null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Test passing NULL to object-related N-APIs. 6 | const { testNull } = require(`./build/${common.buildType}/test_object`); 7 | 8 | const expectedForProperty = { 9 | envIsNull: 'Invalid argument', 10 | objectIsNull: 'Invalid argument', 11 | keyIsNull: 'Invalid argument', 12 | valueIsNull: 'Invalid argument', 13 | }; 14 | assert.deepStrictEqual(testNull.setProperty(), expectedForProperty); 15 | assert.deepStrictEqual(testNull.getProperty(), expectedForProperty); 16 | assert.deepStrictEqual(testNull.hasProperty(), expectedForProperty); 17 | // eslint-disable-next-line no-prototype-builtins 18 | assert.deepStrictEqual(testNull.hasOwnProperty(), expectedForProperty); 19 | // It's OK not to want the result of a deletion. 20 | assert.deepStrictEqual(testNull.deleteProperty(), 21 | Object.assign({}, 22 | expectedForProperty, 23 | { valueIsNull: 'napi_ok' })); 24 | assert.deepStrictEqual(testNull.setNamedProperty(), expectedForProperty); 25 | assert.deepStrictEqual(testNull.getNamedProperty(), expectedForProperty); 26 | assert.deepStrictEqual(testNull.hasNamedProperty(), expectedForProperty); 27 | 28 | const expectedForElement = { 29 | envIsNull: 'Invalid argument', 30 | objectIsNull: 'Invalid argument', 31 | valueIsNull: 'Invalid argument', 32 | }; 33 | assert.deepStrictEqual(testNull.setElement(), expectedForElement); 34 | assert.deepStrictEqual(testNull.getElement(), expectedForElement); 35 | assert.deepStrictEqual(testNull.hasElement(), expectedForElement); 36 | // It's OK not to want the result of a deletion. 37 | assert.deepStrictEqual(testNull.deleteElement(), 38 | Object.assign({}, 39 | expectedForElement, 40 | { valueIsNull: 'napi_ok' })); 41 | 42 | assert.deepStrictEqual(testNull.defineProperties(), { 43 | envIsNull: 'Invalid argument', 44 | objectIsNull: 'Invalid argument', 45 | descriptorListIsNull: 'Invalid argument', 46 | utf8nameIsNull: 'Invalid argument', 47 | methodIsNull: 'Invalid argument', 48 | }); 49 | 50 | // `expectedForElement` also works for the APIs below. 51 | assert.deepStrictEqual(testNull.getPropertyNames(), expectedForElement); 52 | assert.deepStrictEqual(testNull.getAllPropertyNames(), expectedForElement); 53 | assert.deepStrictEqual(testNull.getPrototype(), expectedForElement); 54 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_promise/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_promise", 5 | "sources": [ 6 | "test_promise.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_promise/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const common = require('../../common'); 4 | 5 | // This tests the promise-related n-api calls 6 | 7 | const assert = require('assert'); 8 | const test_promise = require(`./build/${common.buildType}/test_promise`); 9 | 10 | // A resolution 11 | { 12 | const expected_result = 42; 13 | const promise = test_promise.createPromise(); 14 | promise.then( 15 | common.mustCall(function(result) { 16 | assert.strictEqual(result, expected_result); 17 | }), 18 | common.mustNotCall()); 19 | test_promise.concludeCurrentPromise(expected_result, true); 20 | } 21 | 22 | // A rejection 23 | { 24 | const expected_result = 'It\'s not you, it\'s me.'; 25 | const promise = test_promise.createPromise(); 26 | promise.then( 27 | common.mustNotCall(), 28 | common.mustCall(function(result) { 29 | assert.strictEqual(result, expected_result); 30 | })); 31 | test_promise.concludeCurrentPromise(expected_result, false); 32 | } 33 | 34 | // Chaining 35 | { 36 | const expected_result = 'chained answer'; 37 | const promise = test_promise.createPromise(); 38 | promise.then( 39 | common.mustCall(function(result) { 40 | assert.strictEqual(result, expected_result); 41 | }), 42 | common.mustNotCall()); 43 | test_promise.concludeCurrentPromise(Promise.resolve('chained answer'), true); 44 | } 45 | 46 | const promiseTypeTestPromise = test_promise.createPromise(); 47 | assert.strictEqual(test_promise.isPromise(promiseTypeTestPromise), true); 48 | test_promise.concludeCurrentPromise(undefined, true); 49 | 50 | const rejectPromise = Promise.reject(-1); 51 | const expected_reason = -1; 52 | assert.strictEqual(test_promise.isPromise(rejectPromise), true); 53 | rejectPromise.catch((reason) => { 54 | assert.strictEqual(reason, expected_reason); 55 | }); 56 | 57 | assert.strictEqual(test_promise.isPromise(2.4), false); 58 | assert.strictEqual(test_promise.isPromise('I promise!'), false); 59 | assert.strictEqual(test_promise.isPromise(undefined), false); 60 | assert.strictEqual(test_promise.isPromise(null), false); 61 | assert.strictEqual(test_promise.isPromise({}), false); 62 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_promise/test_promise.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | napi_deferred deferred = NULL; 6 | 7 | static napi_value createPromise(napi_env env, napi_callback_info info) { 8 | napi_value promise; 9 | 10 | // We do not overwrite an existing deferred. 11 | if (deferred != NULL) { 12 | return NULL; 13 | } 14 | 15 | NODE_API_CALL(env, napi_create_promise(env, &deferred, &promise)); 16 | 17 | return promise; 18 | } 19 | 20 | static napi_value concludeCurrentPromise(napi_env env, 21 | napi_callback_info info) { 22 | napi_value argv[2]; 23 | size_t argc = 2; 24 | bool resolution; 25 | 26 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); 27 | NODE_API_CALL(env, napi_get_value_bool(env, argv[1], &resolution)); 28 | if (resolution) { 29 | NODE_API_CALL(env, napi_resolve_deferred(env, deferred, argv[0])); 30 | } else { 31 | NODE_API_CALL(env, napi_reject_deferred(env, deferred, argv[0])); 32 | } 33 | 34 | deferred = NULL; 35 | 36 | return NULL; 37 | } 38 | 39 | static napi_value isPromise(napi_env env, napi_callback_info info) { 40 | napi_value promise, result; 41 | size_t argc = 1; 42 | bool is_promise; 43 | 44 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &promise, NULL, NULL)); 45 | NODE_API_CALL(env, napi_is_promise(env, promise, &is_promise)); 46 | NODE_API_CALL(env, napi_get_boolean(env, is_promise, &result)); 47 | 48 | return result; 49 | } 50 | 51 | EXTERN_C_START 52 | napi_value Init(napi_env env, napi_value exports) { 53 | napi_property_descriptor descriptors[] = { 54 | DECLARE_NODE_API_PROPERTY("createPromise", createPromise), 55 | DECLARE_NODE_API_PROPERTY("concludeCurrentPromise", 56 | concludeCurrentPromise), 57 | DECLARE_NODE_API_PROPERTY("isPromise", isPromise), 58 | }; 59 | 60 | NODE_API_CALL( 61 | env, 62 | napi_define_properties(env, 63 | exports, 64 | sizeof(descriptors) / sizeof(*descriptors), 65 | descriptors)); 66 | 67 | return exports; 68 | } 69 | EXTERN_C_END 70 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_properties/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_properties", 5 | "sources": [ 6 | "test_properties.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_properties/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | const readonlyErrorRE = 5 | /^TypeError: Cannot assign to read only property '.*' of object '#'$/; 6 | const getterOnlyErrorRE = 7 | /^TypeError: Cannot set property .* of # which has only a getter$/; 8 | 9 | // Testing api calls for defining properties 10 | const test_object = require(`./build/${common.buildType}/test_properties`); 11 | 12 | assert.strictEqual(test_object.echo('hello'), 'hello'); 13 | 14 | test_object.readwriteValue = 1; 15 | assert.strictEqual(test_object.readwriteValue, 1); 16 | test_object.readwriteValue = 2; 17 | assert.strictEqual(test_object.readwriteValue, 2); 18 | 19 | assert.throws(() => { test_object.readonlyValue = 3; }, readonlyErrorRE); 20 | 21 | assert.ok(test_object.hiddenValue); 22 | 23 | // Properties with napi_enumerable attribute should be enumerable. 24 | const propertyNames = []; 25 | for (const name in test_object) { 26 | propertyNames.push(name); 27 | } 28 | assert.ok(propertyNames.includes('echo')); 29 | assert.ok(propertyNames.includes('readwriteValue')); 30 | assert.ok(propertyNames.includes('readonlyValue')); 31 | assert.ok(!propertyNames.includes('hiddenValue')); 32 | assert.ok(propertyNames.includes('NameKeyValue')); 33 | assert.ok(!propertyNames.includes('readwriteAccessor1')); 34 | assert.ok(!propertyNames.includes('readwriteAccessor2')); 35 | assert.ok(!propertyNames.includes('readonlyAccessor1')); 36 | assert.ok(!propertyNames.includes('readonlyAccessor2')); 37 | 38 | // Validate properties created with symbol 39 | const propertySymbols = Object.getOwnPropertySymbols(test_object); 40 | assert.strictEqual(propertySymbols[0].toString(), 'Symbol(NameKeySymbol)'); 41 | assert.strictEqual(propertySymbols[1].toString(), 'Symbol()'); 42 | assert.strictEqual(propertySymbols[2], Symbol.for('NameKeySymbolFor')); 43 | 44 | // The napi_writable attribute should be ignored for accessors. 45 | const readwriteAccessor1Descriptor = 46 | Object.getOwnPropertyDescriptor(test_object, 'readwriteAccessor1'); 47 | const readonlyAccessor1Descriptor = 48 | Object.getOwnPropertyDescriptor(test_object, 'readonlyAccessor1'); 49 | assert.ok(readwriteAccessor1Descriptor.get != null); 50 | assert.ok(readwriteAccessor1Descriptor.set != null); 51 | assert.ok(readwriteAccessor1Descriptor.value === undefined); 52 | assert.ok(readonlyAccessor1Descriptor.get != null); 53 | assert.ok(readonlyAccessor1Descriptor.set === undefined); 54 | assert.ok(readonlyAccessor1Descriptor.value === undefined); 55 | test_object.readwriteAccessor1 = 1; 56 | assert.strictEqual(test_object.readwriteAccessor1, 1); 57 | assert.strictEqual(test_object.readonlyAccessor1, 1); 58 | assert.throws(() => { test_object.readonlyAccessor1 = 3; }, getterOnlyErrorRE); 59 | test_object.readwriteAccessor2 = 2; 60 | assert.strictEqual(test_object.readwriteAccessor2, 2); 61 | assert.strictEqual(test_object.readonlyAccessor2, 2); 62 | assert.throws(() => { test_object.readonlyAccessor2 = 3; }, getterOnlyErrorRE); 63 | 64 | assert.strictEqual(test_object.hasNamedProperty(test_object, 'echo'), true); 65 | assert.strictEqual(test_object.hasNamedProperty(test_object, 'hiddenValue'), 66 | true); 67 | assert.strictEqual(test_object.hasNamedProperty(test_object, 'doesnotexist'), 68 | false); 69 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_reference", 5 | "sources": [ 6 | "test_reference.c" 7 | ] 8 | }, 9 | { 10 | "target_name": "test_finalizer", 11 | "sources": [ 12 | "test_finalizer.c" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference/test_finalizer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../common.h" 5 | #include "../entry_point.h" 6 | 7 | static int test_value = 1; 8 | static int finalize_count = 0; 9 | 10 | static void FinalizeExternalCallJs(napi_env env, void* data, void* hint) { 11 | int* actual_value = data; 12 | NODE_API_ASSERT_RETURN_VOID( 13 | env, 14 | actual_value == &test_value, 15 | "The correct pointer was passed to the finalizer"); 16 | 17 | napi_ref finalizer_ref = (napi_ref)hint; 18 | napi_value js_finalizer; 19 | napi_value recv; 20 | NODE_API_CALL_RETURN_VOID( 21 | env, napi_get_reference_value(env, finalizer_ref, &js_finalizer)); 22 | NODE_API_CALL_RETURN_VOID(env, napi_get_global(env, &recv)); 23 | NODE_API_CALL_RETURN_VOID( 24 | env, napi_call_function(env, recv, js_finalizer, 0, NULL, NULL)); 25 | NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, finalizer_ref)); 26 | } 27 | 28 | static napi_value CreateExternalWithJsFinalize(napi_env env, 29 | napi_callback_info info) { 30 | size_t argc = 1; 31 | napi_value args[1]; 32 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 33 | NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments"); 34 | napi_value finalizer = args[0]; 35 | napi_valuetype finalizer_valuetype; 36 | NODE_API_CALL(env, napi_typeof(env, finalizer, &finalizer_valuetype)); 37 | NODE_API_ASSERT(env, 38 | finalizer_valuetype == napi_function, 39 | "Wrong type of first argument"); 40 | napi_ref finalizer_ref; 41 | NODE_API_CALL(env, napi_create_reference(env, finalizer, 1, &finalizer_ref)); 42 | 43 | napi_value result; 44 | NODE_API_CALL(env, 45 | napi_create_external(env, 46 | &test_value, 47 | FinalizeExternalCallJs, 48 | finalizer_ref, /* finalize_hint */ 49 | &result)); 50 | 51 | finalize_count = 0; 52 | return result; 53 | } 54 | 55 | EXTERN_C_START 56 | napi_value Init(napi_env env, napi_value exports) { 57 | napi_property_descriptor descriptors[] = { 58 | DECLARE_NODE_API_PROPERTY("createExternalWithJsFinalize", 59 | CreateExternalWithJsFinalize), 60 | }; 61 | 62 | NODE_API_CALL( 63 | env, 64 | napi_define_properties(env, 65 | exports, 66 | sizeof(descriptors) / sizeof(*descriptors), 67 | descriptors)); 68 | 69 | return exports; 70 | } 71 | EXTERN_C_END 72 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference/test_finalizer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | 4 | if (process.argv[2] === 'child') { 5 | const binding = require(`./build/${common.buildType}/test_ref_finalizer`); 6 | 7 | (async function() { 8 | { 9 | binding.createExternalWithJsFinalize( 10 | common.mustCall(() => { 11 | throw new Error('finalizer error'); 12 | })); 13 | } 14 | global.gc(); 15 | })().then(common.mustCall()); 16 | return; 17 | } 18 | 19 | const assert = require('assert'); 20 | const { spawnSync } = require('child_process'); 21 | const child = spawnSync(process.execPath, [ 22 | '--expose-gc', __filename, 'child', 23 | ]); 24 | assert(common.nodeProcessAborted(child.status, child.signal)); 25 | assert.match(child.stderr.toString(), /finalizer error/); 26 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference_double_free/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_reference_double_free", 5 | "sources": [ 6 | "test_reference_double_free.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference_double_free/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This test makes no assertions. It tests a fix without which it will crash 4 | // with a double free. 5 | 6 | const { buildType } = require('../../common'); 7 | 8 | const addon = require(`./build/${buildType}/test_reference_double_free`); 9 | 10 | { new addon.MyObject(true); } 11 | { new addon.MyObject(false); } 12 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference_double_free/test_reference_double_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../common.h" 4 | #include "../entry_point.h" 5 | 6 | static size_t g_call_count = 0; 7 | 8 | static void Destructor(napi_env env, void* data, void* nothing) { 9 | napi_ref* ref = data; 10 | NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref)); 11 | free(ref); 12 | } 13 | 14 | static void NoDeleteDestructor(napi_env env, void* data, void* hint) { 15 | napi_ref* ref = data; 16 | size_t* call_count = hint; 17 | 18 | // This destructor must be called exactly once. 19 | if ((*call_count) > 0) abort(); 20 | *call_count = ((*call_count) + 1); 21 | free(ref); 22 | } 23 | 24 | static napi_value New(napi_env env, napi_callback_info info) { 25 | size_t argc = 1; 26 | napi_value js_this, js_delete; 27 | bool delete; 28 | napi_ref* ref = malloc(sizeof(*ref)); 29 | 30 | NODE_API_CALL(env, 31 | napi_get_cb_info(env, info, &argc, &js_delete, &js_this, NULL)); 32 | NODE_API_CALL(env, napi_get_value_bool(env, js_delete, &delete)); 33 | 34 | if (delete) { 35 | NODE_API_CALL(env, napi_wrap(env, js_this, ref, Destructor, NULL, ref)); 36 | } else { 37 | NODE_API_CALL( 38 | env, 39 | napi_wrap(env, js_this, ref, NoDeleteDestructor, &g_call_count, ref)); 40 | } 41 | NODE_API_CALL(env, napi_reference_ref(env, *ref, NULL)); 42 | 43 | return js_this; 44 | } 45 | 46 | static void NoopDeleter(napi_env env, void* data, void* hint) {} 47 | 48 | // Tests that calling napi_remove_wrap and napi_delete_reference consecutively 49 | // doesn't crash the process. 50 | // This is analogous to the test 51 | // https://github.com/nodejs/node-addon-api/blob/main/test/objectwrap_constructor_exception.cc. 52 | // In which the Napi::ObjectWrap<> is being destructed immediately after 53 | // napi_wrap. As Napi::ObjectWrap<> is a subclass of Napi::Reference<>, 54 | // napi_remove_wrap in the destructor of Napi::ObjectWrap<> is called before 55 | // napi_delete_reference in the destructor of Napi::Reference<>. 56 | static napi_value DeleteImmediately(napi_env env, napi_callback_info info) { 57 | size_t argc = 1; 58 | napi_value js_obj; 59 | napi_ref ref; 60 | napi_valuetype type; 61 | 62 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &js_obj, NULL, NULL)); 63 | 64 | NODE_API_CALL(env, napi_typeof(env, js_obj, &type)); 65 | NODE_API_ASSERT(env, type == napi_object, "Expected object parameter"); 66 | 67 | NODE_API_CALL(env, napi_wrap(env, js_obj, NULL, NoopDeleter, NULL, &ref)); 68 | NODE_API_CALL(env, napi_remove_wrap(env, js_obj, NULL)); 69 | NODE_API_CALL(env, napi_delete_reference(env, ref)); 70 | 71 | return NULL; 72 | } 73 | 74 | EXTERN_C_START 75 | napi_value Init(napi_env env, napi_value exports) { 76 | napi_value myobj_ctor; 77 | NODE_API_CALL( 78 | env, 79 | napi_define_class( 80 | env, "MyObject", NAPI_AUTO_LENGTH, New, NULL, 0, NULL, &myobj_ctor)); 81 | NODE_API_CALL(env, 82 | napi_set_named_property(env, exports, "MyObject", myobj_ctor)); 83 | 84 | napi_property_descriptor descriptors[] = { 85 | DECLARE_NODE_API_PROPERTY("deleteImmediately", DeleteImmediately), 86 | }; 87 | NODE_API_CALL( 88 | env, 89 | napi_define_properties(env, 90 | exports, 91 | sizeof(descriptors) / sizeof(*descriptors), 92 | descriptors)); 93 | 94 | return exports; 95 | } 96 | EXTERN_C_END 97 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_reference_double_free/test_wrap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This test makes no assertions. It tests that calling napi_remove_wrap and 4 | // napi_delete_reference consecutively doesn't crash the process. 5 | 6 | const { buildType } = require('../../common'); 7 | 8 | const addon = require(`./build/${buildType}/test_reference_double_free`); 9 | 10 | addon.deleteImmediately({}); 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_string/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_string", 5 | "sources": [ 6 | "test_string.c", 7 | "test_null.c", 8 | ], 9 | "defines": [ 10 | "NAPI_EXPERIMENTAL", 11 | ], 12 | }, 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_string/test_null.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../common.h" 4 | #include "test_null.h" 5 | 6 | #define DECLARE_TEST(charset, str_arg) \ 7 | static napi_value test_create_##charset(napi_env env, \ 8 | napi_callback_info info) { \ 9 | napi_value return_value, result; \ 10 | NODE_API_CALL(env, napi_create_object(env, &return_value)); \ 11 | \ 12 | add_returned_status(env, \ 13 | "envIsNull", \ 14 | return_value, \ 15 | "Invalid argument", \ 16 | napi_invalid_arg, \ 17 | napi_create_string_##charset( \ 18 | NULL, (str_arg), NAPI_AUTO_LENGTH, &result)); \ 19 | \ 20 | napi_create_string_##charset(env, NULL, NAPI_AUTO_LENGTH, &result); \ 21 | add_last_status(env, "stringIsNullNonZeroLength", return_value); \ 22 | \ 23 | napi_create_string_##charset(env, NULL, 0, &result); \ 24 | add_last_status(env, "stringIsNullZeroLength", return_value); \ 25 | \ 26 | napi_create_string_##charset(env, (str_arg), NAPI_AUTO_LENGTH, NULL); \ 27 | add_last_status(env, "resultIsNull", return_value); \ 28 | \ 29 | return return_value; \ 30 | } 31 | 32 | static const char16_t something[] = {(char16_t)'s', 33 | (char16_t)'o', 34 | (char16_t)'m', 35 | (char16_t)'e', 36 | (char16_t)'t', 37 | (char16_t)'h', 38 | (char16_t)'i', 39 | (char16_t)'n', 40 | (char16_t)'g', 41 | (char16_t)'\0'}; 42 | 43 | DECLARE_TEST(utf8, "something") 44 | DECLARE_TEST(latin1, "something") 45 | DECLARE_TEST(utf16, something) 46 | 47 | void init_test_null(napi_env env, napi_value exports) { 48 | napi_value test_null; 49 | 50 | const napi_property_descriptor test_null_props[] = { 51 | DECLARE_NODE_API_PROPERTY("test_create_utf8", test_create_utf8), 52 | DECLARE_NODE_API_PROPERTY("test_create_latin1", test_create_latin1), 53 | DECLARE_NODE_API_PROPERTY("test_create_utf16", test_create_utf16), 54 | }; 55 | 56 | NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &test_null)); 57 | NODE_API_CALL_RETURN_VOID( 58 | env, 59 | napi_define_properties(env, 60 | test_null, 61 | sizeof(test_null_props) / sizeof(*test_null_props), 62 | test_null_props)); 63 | 64 | const napi_property_descriptor test_null_set = { 65 | "testNull", NULL, NULL, NULL, NULL, test_null, napi_enumerable, NULL}; 66 | 67 | NODE_API_CALL_RETURN_VOID( 68 | env, napi_define_properties(env, exports, 1, &test_null_set)); 69 | } 70 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_string/test_null.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_JS_NATIVE_API_TEST_STRING_TEST_NULL_H_ 2 | #define TEST_JS_NATIVE_API_TEST_STRING_TEST_NULL_H_ 3 | 4 | #include 5 | 6 | void init_test_null(napi_env env, napi_value exports); 7 | 8 | #endif // TEST_JS_NATIVE_API_TEST_STRING_TEST_NULL_H_ 9 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_string/test_null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Test passing NULL to object-related N-APIs. 6 | const { testNull } = require(`./build/${common.buildType}/test_string`); 7 | 8 | const expectedResult = { 9 | envIsNull: 'Invalid argument', 10 | stringIsNullNonZeroLength: 'Invalid argument', 11 | stringIsNullZeroLength: 'napi_ok', 12 | resultIsNull: 'Invalid argument', 13 | }; 14 | 15 | assert.deepStrictEqual(expectedResult, testNull.test_create_latin1()); 16 | assert.deepStrictEqual(expectedResult, testNull.test_create_utf8()); 17 | assert.deepStrictEqual(expectedResult, testNull.test_create_utf16()); 18 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_symbol/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_symbol", 5 | "sources": [ 6 | "test_symbol.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_symbol/test1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for symbol 6 | const test_symbol = require(`./build/${common.buildType}/test_symbol`); 7 | 8 | const sym = test_symbol.New('test'); 9 | assert.strictEqual(sym.toString(), 'Symbol(test)'); 10 | 11 | const myObj = {}; 12 | const fooSym = test_symbol.New('foo'); 13 | const otherSym = test_symbol.New('bar'); 14 | myObj.foo = 'bar'; 15 | myObj[fooSym] = 'baz'; 16 | myObj[otherSym] = 'bing'; 17 | assert.strictEqual(myObj.foo, 'bar'); 18 | assert.strictEqual(myObj[fooSym], 'baz'); 19 | assert.strictEqual(myObj[otherSym], 'bing'); 20 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_symbol/test2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for symbol 6 | const test_symbol = require(`./build/${common.buildType}/test_symbol`); 7 | 8 | const fooSym = test_symbol.New('foo'); 9 | assert.strictEqual(fooSym.toString(), 'Symbol(foo)'); 10 | 11 | const myObj = {}; 12 | myObj.foo = 'bar'; 13 | myObj[fooSym] = 'baz'; 14 | 15 | assert.deepStrictEqual(Object.keys(myObj), ['foo']); 16 | assert.deepStrictEqual(Object.getOwnPropertyNames(myObj), ['foo']); 17 | assert.deepStrictEqual(Object.getOwnPropertySymbols(myObj), [fooSym]); 18 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_symbol/test3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const common = require('../../common'); 3 | const assert = require('assert'); 4 | 5 | // Testing api calls for symbol 6 | const test_symbol = require(`./build/${common.buildType}/test_symbol`); 7 | 8 | assert.notStrictEqual(test_symbol.New(), test_symbol.New()); 9 | assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('foo')); 10 | assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('bar')); 11 | 12 | const foo1 = test_symbol.New('foo'); 13 | const foo2 = test_symbol.New('foo'); 14 | const object = { 15 | [foo1]: 1, 16 | [foo2]: 2, 17 | }; 18 | assert.strictEqual(object[foo1], 1); 19 | assert.strictEqual(object[foo2], 2); 20 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_symbol/test_symbol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../common.h" 3 | #include "../entry_point.h" 4 | 5 | static napi_value New(napi_env env, napi_callback_info info) { 6 | size_t argc = 1; 7 | napi_value args[1]; 8 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 9 | 10 | napi_value description = NULL; 11 | if (argc >= 1) { 12 | napi_valuetype valuetype; 13 | NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype)); 14 | 15 | NODE_API_ASSERT(env, 16 | valuetype == napi_string, 17 | "Wrong type of arguments. Expects a string."); 18 | 19 | description = args[0]; 20 | } 21 | 22 | napi_value symbol; 23 | NODE_API_CALL(env, napi_create_symbol(env, description, &symbol)); 24 | 25 | return symbol; 26 | } 27 | 28 | EXTERN_C_START 29 | napi_value Init(napi_env env, napi_value exports) { 30 | napi_property_descriptor properties[] = { 31 | DECLARE_NODE_API_PROPERTY("New", New), 32 | }; 33 | 34 | NODE_API_CALL( 35 | env, 36 | napi_define_properties( 37 | env, exports, sizeof(properties) / sizeof(*properties), properties)); 38 | 39 | return exports; 40 | } 41 | EXTERN_C_END 42 | -------------------------------------------------------------------------------- /src/node-api/test/js-native-api/test_typedarray/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "test_typedarray", 5 | "sources": [ 6 | "test_typedarray.c" 7 | ] 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/node-api/test/node_api_test_v8.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | #include "node_api_test.h" 5 | #include "v8_api.h" 6 | 7 | namespace node_api_tests { 8 | 9 | class V8RuntimeHolder : public IEnvHolder { 10 | public: 11 | V8RuntimeHolder(std::shared_ptr taskRunner) noexcept { 12 | jsr_config config{}; 13 | jsr_create_config(&config); 14 | jsr_config_enable_gc_api(config, true); 15 | std::shared_ptr* taskRunnerPtr = 16 | new std::shared_ptr(std::move(taskRunner)); 17 | jsr_config_set_task_runner(config, 18 | taskRunnerPtr, 19 | NodeApiTaskRunner::PostTaskCallback, 20 | NodeApiTaskRunner::DeleteCallback, 21 | nullptr); 22 | jsr_create_runtime(config, &runtime_); 23 | jsr_delete_config(config); 24 | jsr_runtime_get_node_api_env(runtime_, &env_); 25 | } 26 | 27 | ~V8RuntimeHolder() { jsr_delete_runtime(runtime_); } 28 | 29 | V8RuntimeHolder(const V8RuntimeHolder&) = delete; 30 | V8RuntimeHolder& operator=(const V8RuntimeHolder&) = delete; 31 | 32 | napi_env getEnv() override { return env_; } 33 | 34 | private: 35 | jsr_runtime runtime_{}; 36 | napi_env env_{}; 37 | }; 38 | 39 | std::unique_ptr CreateEnvHolder( 40 | std::shared_ptr taskRunner) { 41 | return std::unique_ptr( 42 | new V8RuntimeHolder(std::move(taskRunner))); 43 | } 44 | 45 | } // namespace node_api_tests 46 | -------------------------------------------------------------------------------- /src/public/Readme.md: -------------------------------------------------------------------------------- 1 | # V8JSI Public API 2 | 3 | This folder contains the public API for the V8JSI.DLL. 4 | 5 | The js_native_api.h and js_native_api_types.h files are the N-API header files 6 | taken from the Node.js project. See the Node.js project repo for the license: 7 | https://github.com/nodejs/node -------------------------------------------------------------------------------- /src/public/ScriptStore.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | namespace facebook { 9 | namespace jsi { 10 | 11 | // Integer type as it's persist friendly. 12 | using ScriptVersion_t = uint64_t; // It should be std::optional once we have c++17 available everywhere. Until 13 | // then, 0 implies versioning not available. 14 | using JSRuntimeVersion_t = uint64_t; // 0 implies version can't be computed. We assert whenever that happens. 15 | 16 | struct VersionedBuffer { 17 | std::shared_ptr buffer; 18 | ScriptVersion_t version; 19 | }; 20 | 21 | struct ScriptSignature { 22 | std::string url; 23 | ScriptVersion_t version; 24 | }; 25 | 26 | struct JSRuntimeSignature { 27 | std::string runtimeName; // e.g. Chakra, V8 28 | JSRuntimeVersion_t version; 29 | }; 30 | 31 | // Most JSI::Runtime implementation offer some form of prepared JavaScript which offers better performance 32 | // characteristics when loading comparing to plain JavaScript. Embedders can provide an instance of this interface 33 | // (through JSI::Runtime implementation's factory method), to enable persistance of the prepared script and retrieval on 34 | // subsequent evaluation of a script. 35 | struct PreparedScriptStore { 36 | virtual ~PreparedScriptStore() = default; 37 | 38 | // Try to retrieve the prepared javascript for a given combination of script & runtime. 39 | // scriptSignature : Javascript url and version 40 | // RuntimeSignature : Javascript engine type and version 41 | // prepareTag : Custom tag to uniquely identify JS engine specific preparation schemes. It is usually useful while 42 | // experimentation and can be null. It is possible that no prepared script is available for a given script & runtime 43 | // signature. This method should null if so 44 | virtual std::shared_ptr tryGetPreparedScript( 45 | const ScriptSignature &scriptSignature, 46 | const JSRuntimeSignature &runtimeSignature, 47 | const char *prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. 48 | ) noexcept = 0; 49 | 50 | // Persist the perpared javascript for a given combination of script & runtime. 51 | // scriptSignature : Javascript url and version 52 | // RuntimeSignature : Javascript engine type and version 53 | // prepareTag : Custom tag to uniquely identify JS engine specific preparation schemes. It is usually useful while 54 | // experimentation and can be null. It is possible that no prepared script is available for a given script & runtime 55 | // signature. This method should null if so Any failure in persistance should be identified during the subsequent 56 | // retrieval through the integrity mechanism which must be put into the storage. 57 | virtual void persistPreparedScript( 58 | std::shared_ptr preparedScript, 59 | const ScriptSignature &scriptMetadata, 60 | const JSRuntimeSignature &runtimeMetadata, 61 | const char *prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. 62 | ) noexcept = 0; 63 | }; 64 | 65 | // JSI::Runtime implementation must be provided an instance on this interface to enable version sensitive capabilities 66 | // such as usage of pre-prepared javascript script. Alternatively, this entity can be used to directly provide the 67 | // Javascript buffer and rich metadata to the JSI::Runtime instance. 68 | struct ScriptStore { 69 | virtual ~ScriptStore() = default; 70 | 71 | // Return the Javascript buffer and version corresponding to a given url. 72 | virtual VersionedBuffer getVersionedScript(const std::string &url) noexcept = 0; 73 | 74 | // Return the version of the Javascript buffer corresponding to a given url. 75 | virtual ScriptVersion_t getScriptVersion(const std::string &url) noexcept = 0; 76 | }; 77 | 78 | } // namespace jsi 79 | } // namespace facebook 80 | -------------------------------------------------------------------------------- /src/public/compat.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | #ifndef SRC_PUBLIC_COMPAT_H_ 6 | #define SRC_PUBLIC_COMPAT_H_ 7 | 8 | // This file contains some useful datatypes recently introduced in C++17 and C++20. 9 | // They must be removed after we switch the toolset to the newer C++ language version. 10 | 11 | #include 12 | #ifdef __cpp_lib_span 13 | #include 14 | #endif 15 | 16 | namespace napijsi { 17 | 18 | #ifdef __cpp_lib_span 19 | using std::span; 20 | #else 21 | /** 22 | * @brief A span of values that can be used to pass arguments to function. 23 | * 24 | * For C++20 we should consider to replace it with std::span. 25 | */ 26 | template 27 | struct span { 28 | constexpr span(std::initializer_list il) noexcept : data_{const_cast(il.begin())}, size_{il.size()} {} 29 | constexpr span(T *data, size_t size) noexcept : data_{data}, size_{size} {} 30 | 31 | [[nodiscard]] constexpr T *data() const noexcept { 32 | return data_; 33 | } 34 | 35 | [[nodiscard]] constexpr size_t size() const noexcept { 36 | return size_; 37 | } 38 | 39 | [[nodiscard]] constexpr T *begin() const noexcept { 40 | return data_; 41 | } 42 | 43 | [[nodiscard]] constexpr T *end() const noexcept { 44 | return data_ + size_; 45 | } 46 | 47 | const T &operator[](size_t index) const noexcept { 48 | return *(data_ + index); 49 | } 50 | 51 | private: 52 | T *data_; 53 | size_t size_; 54 | }; 55 | #endif // __cpp_lib_span 56 | 57 | } // namespace napijsi 58 | 59 | #endif // SRC_PUBLIC_COMPAT_H_ 60 | -------------------------------------------------------------------------------- /src/public/v8_api.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | #ifndef V8_API_H_ 5 | #define V8_API_H_ 6 | 7 | #include "js_runtime_api.h" 8 | 9 | EXTERN_C_START 10 | 11 | JSR_API v8_config_enable_multithreading(jsr_config config, bool value); 12 | 13 | JSR_API v8_platform_dispose(); 14 | 15 | EXTERN_C_END 16 | 17 | #endif // V8_API_H_ 18 | -------------------------------------------------------------------------------- /src/source_link.json: -------------------------------------------------------------------------------- 1 | { 2 | "documents": { 3 | "LOCAL_PATH\\build\\v8\\*" : "https://raw.githubusercontent.com/v8/v8/V8JSIVER_V8REF/*", 4 | "LOCAL_PATH\\build\\v8\\jsi\\*" : "https://raw.githubusercontent.com/microsoft/v8-jsi/V8JSI_GIT_HASH/src/*" 5 | } 6 | } -------------------------------------------------------------------------------- /src/version.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // A PowerShell script replaces the tokens with actual version information 4 | 5 | VS_VERSION_INFO VERSIONINFO 6 | FILEVERSION V8JSIVER_MAJOR,V8JSIVER_MINOR,V8JSIVER_BUILD,0 7 | PRODUCTVERSION V8JSIVER_MAJOR,V8JSIVER_MINOR,V8JSIVER_BUILD,0 8 | FILEFLAGSMASK 0x17L 9 | #ifdef _DEBUG 10 | FILEFLAGS 0x1L 11 | #else 12 | FILEFLAGS 0x0L 13 | #endif 14 | FILEOS 0x4L 15 | FILETYPE 0x1L 16 | FILESUBTYPE 0x0L 17 | BEGIN 18 | BLOCK "StringFileInfo" 19 | BEGIN 20 | BLOCK "040904b0" 21 | BEGIN 22 | VALUE "CompanyName", "Microsoft" 23 | VALUE "FileDescription", "React Native V8 JSI Adapter" 24 | VALUE "FileVersion", "V8JSIVER_MAJOR.V8JSIVER_MINOR.V8JSIVER_BUILD.V8JSIVER_V8REF" 25 | VALUE "InternalName", "v8jsi.dll" 26 | VALUE "LegalCopyright", "(c) Microsoft Corporation." 27 | VALUE "OriginalFilename", "v8jsi.dll" 28 | VALUE "ProductName", "React Native V8 JSI Adapter" 29 | VALUE "ProductVersion", "V8JSIVER_MAJOR.V8JSIVER_MINOR.V8JSIVER_BUILD.V8JSIVER_V8REF" 30 | VALUE "CompanyShortName", "Microsoft" 31 | VALUE "ProductShortName", "V8JSI" 32 | END 33 | END 34 | BLOCK "VarFileInfo" 35 | BEGIN 36 | VALUE "Translation", 0x409, 1200 37 | END 38 | END 39 | 40 | --------------------------------------------------------------------------------