diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..01a20f1
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+# https://editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/.github/workflows/build-android.yaml b/.github/workflows/build-android.yaml
deleted file mode 100644
index 9d2ad65..0000000
--- a/.github/workflows/build-android.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: Build Android Project
-on:
- push:
- branches: [ unstable ]
- pull_request:
- branches: [ unstable ]
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Clone repo
- uses: actions/checkout@v2
- - name: Installing JDK 8
- uses: actions/setup-java@v2
- with:
- distribution: 'zulu'
- java-version: '8'
- - name: Installing Cordova!
- run: |
- sudo npm i cordova@10.0.0 -g
- - name: Installing the npm dependencies!
- run: |
- cd testapp
- npm i
- - name: Copying nodejs-mobile-cordova plugin
- run: |
- cd testapp
- npm run copy-module
- - name: Preparing the Android project!
- run: |
- cd testapp
- cordova prepare android
- - name: Building the Android project!
- run: |
- cd testapp
- cordova build android
diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml
new file mode 100644
index 0000000..141bc1f
--- /dev/null
+++ b/.github/workflows/build-android.yml
@@ -0,0 +1,30 @@
+name: Build Android Project
+on:
+ pull_request:
+ push:
+ branches: [main]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Clone repo
+ uses: actions/checkout@v4
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: ".node-version"
+ - name: set up JDK 11
+ uses: actions/setup-java@v4
+ with:
+ distribution: "temurin"
+ java-version: "11"
+ - name: Installing Cordova!
+ run: |
+ sudo npm i cordova -g
+ - name: npm install, build, and test
+ run: |
+ npm ci
+ npm run test:build --if-present
+ env:
+ CI: true
diff --git a/.github/workflows/build-ios.yaml b/.github/workflows/build-ios.yaml
deleted file mode 100644
index 8d91f3f..0000000
--- a/.github/workflows/build-ios.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: Build IOS Project
-on:
- push:
- branches: [ unstable ]
- pull_request:
- branches: [ unstable ]
-
-jobs:
- build:
- runs-on: macOS-latest
- steps:
- - name: Clone repo
- uses: actions/checkout@v2
- - name: Installing Cordova!
- run: |
- sudo npm i cordova@10.0.0 -g
- - name: Installing the npm dependencies!
- run: |
- cd testapp
- npm i
- - name: Copying nodejs-mobile-cordova plugin
- run: |
- cd testapp
- npm run copy-module
- - name: Preparing the IOS project!
- run: |
- cd testapp
- cordova prepare ios
- - name: Building the ISO project!
- run: |
- cd testapp
- cordova build ios
diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
new file mode 100644
index 0000000..a2a4c3a
--- /dev/null
+++ b/.github/workflows/npm-publish.yml
@@ -0,0 +1,33 @@
+name: npm publish
+
+on:
+ workflow_run:
+ workflows: [Build Android Project]
+ branches: [main]
+ types: [completed]
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+ - uses: JS-DevTools/npm-publish@v3
+ id: publish
+ with:
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Create Release
+ if: ${{ steps.publish.outputs.type }}
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.publish.outputs.version }}
+ release_name: Release ${{ steps.publish.outputs.version }}
+ body: ${{ steps.publish.outputs.version }}
+ draft: false
+ prerelease: false
diff --git a/.gitignore b/.gitignore
index 4926076..1be3b22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,182 @@
-.vscode/
-node_modules/
\ No newline at end of file
+# Created by https://www.toptal.com/developers/gitignore/api/macos
+# Edit at https://www.toptal.com/developers/gitignore?templates=macos
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### macOS Patch ###
+# iCloud generated files
+*.icloud
+
+# End of https://www.toptal.com/developers/gitignore/api/macos
+
+# Created by https://www.toptal.com/developers/gitignore/api/node
+# Edit at https://www.toptal.com/developers/gitignore?templates=node
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+### Node Patch ###
+# Serverless Webpack directories
+.webpack/
+
+# Optional stylelint cache
+
+# SvelteKit build / generate output
+.svelte-kit
+
+# End of https://www.toptal.com/developers/gitignore/api/node
diff --git a/.node-version b/.node-version
new file mode 100644
index 0000000..a9d0873
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+18.19.0
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..a4ebb87
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,20 @@
+# Testing, code coverage, and linting
+.eslintignore
+.eslintrc.yml
+.jshinrc
+.node-version
+.editorconfig
+
+# Git
+.git
+.gitattributes
+.gitignore
+
+# Github
+.github
+
+# test
+tests/
+testapp/
+
+zipLibNode.js
diff --git a/README.md b/README.md
index feb1eec..772e648 100644
--- a/README.md
+++ b/README.md
@@ -3,24 +3,25 @@
## Installation
```bash
-$ cordova plugin add nodejs-mobile-cordova
+% cordova plugin add nodejs-mobile-cordova
```
## Requirements
- - Cordova 9.x or higher
- - iOS 11 or higher
- - Android API 22 or higher
+- Cordova 12.x or higher
+- Android API 24 or higher
+- iOS 11 or higher
When building an application for the Android platform, make sure you have the [Android NDK](https://developer.android.com/ndk/index.html) installed and the environment variable `ANDROID_NDK_HOME` set, for example:
+
```bash
-$ export ANDROID_NDK_HOME=/Users/username/Library/Android/sdk/ndk-bundle
+% export ANDROID_NDK_HOME=/Users/username/Library/Android/sdk/ndk-bundle
```
## Supported Platforms
-- Android (ARMv7a, x86)
-- iOS (ARM64)
+- Android (ARMv7a, ARM64)
+- iOS (arm64)
## Reporting Issues
@@ -30,6 +31,7 @@ So please, open the issue [there](https://github.com/janeasystems/nodejs-mobile/
## Methods available in the Cordova layer
These methods can be called from the Cordova javascript code directly:
+
- `nodejs.start`
- `nodejs.startWithScript`
- `nodejs.channel.on`
@@ -41,65 +43,65 @@ These methods can be called from the Cordova javascript code directly:
### nodejs.start(scriptFileName, callback [, options])
-| Param | Type |
-| --- | --- |
-| scriptFileName | string
|
-| callback | function
|
-| options | [StartupOptions](#cordova.StartupOptions)
|
+| Param | Type |
+| -------------- | ------------------------------------------- |
+| scriptFileName | `string` |
+| callback | `function` |
+| options | `[StartupOptions](#cordova.StartupOptions)` |
Starts the nodejs-mobile runtime thread with a file inside the `nodejs-project` directory.
### nodejs.startWithScript(scriptBody, callback [, options])
-| Param | Type |
-| --- | --- |
-| scriptBody | string
|
-| callback | function
|
-| options | [StartupOptions](#cordova.StartupOptions)
|
+| Param | Type |
+| ---------- | ------------------------------------------- |
+| scriptBody | `string` |
+| callback | `function` |
+| options | `[StartupOptions](#cordova.StartupOptions)` |
Starts the nodejs-mobile runtime thread with a script body.
### nodejs.channel.on(event, callback)
-| Param | Type |
-| --- | --- |
-| event | string
|
-| callback | [function](#cordova.channelCallback)
|
+| Param | Type |
+| -------- | -------------------------------------- |
+| event | `string` |
+| callback | `[function](#cordova.channelCallback)` |
Registers a callback for user-defined events raised from the nodejs-mobile side.
### nodejs.channel.post(event, message)
-| Param | Type |
-| --- | --- |
-| event | string
|
+| Param | Type |
+| ------- | ------------------------------------------------------------------------------------------- |
+| event | `string` |
| message | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
Raises a user-defined event on the nodejs-mobile side.
### nodejs.channel.setListener(listenerCallback)
-| Param | Type |
-| --- | --- |
-| listenerCallback | [function](#cordova.channelCallback)
|
+| Param | Type |
+| ---------------- | -------------------------------------- |
+| listenerCallback | `[function](#cordova.channelCallback)` |
Registers a callback for 'message' events raised from the nodejs-mobile side.
It is an alias for `nodejs.channel.on('message', listenerCallback);`.
### nodejs.channel.send(message)
-| Param | Type |
-| --- | --- |
+| Param | Type |
+| ------- | ------------------------------------------------------------------------------------------- |
| message | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
Raises a 'message' event on the nodejs-mobile side.
It is an alias for `nodejs.channel.post('message', message);`.
-
-### StartupOptions: object
-| Name | Type | Default | Description |
-| --- | --- | --- | --- |
-| redirectOutputToLogcat | boolean
| true
| Allows to disable the redirection of the Node stdout/stderr to the Android logcat |
+### StartupOptions: `object`
+
+| Name | Type | Default | Description |
+| ---------------------- | --------- | ------- | --------------------------------------------------------------------------------- |
+| redirectOutputToLogcat | `boolean` | `true` | Allows to disable the redirection of the Node stdout/stderr to the Android logcat |
Note: the stdout/stderr redirection is applied to the whole application, the side effect is that some undesired/duplicated output may appear in the logcat.
For example, the Chromium console output `I/chromium: [INFO:CONSOLE(xx)]` is also sent to stderr and will show up in logcat has well, with the `NODEJS-MOBILE` log tag.
@@ -107,8 +109,9 @@ For example, the Chromium console output `I/chromium: [INFO:CONSOLE(xx)]` is als
## Methods available in the Node layer
The following methods can be called from the Node javascript code through the `cordova-bridge` module:
+
```js
- var cordova = require('cordova-bridge');
+var cordova = require("cordova-bridge");
```
- `cordova.channel.on`
@@ -121,31 +124,32 @@ The following methods can be called from the Node javascript code through the `c
### cordova.channel.on(event, callback)
-| Param | Type |
-| --- | --- |
-| event | string
|
-| callback | [function](#cordova.channelCallback)
|
+| Param | Type |
+| -------- | -------------------------------------- |
+| event | `string` |
+| callback | `[function](#cordova.channelCallback)` |
Registers a callback for user-defined events raised from the cordova side.
-> To receive messages from `nodejs.channel.send`, use:
+> To receive messages from `nodejs.channel.send`, use
+>
> ```js
-> cordova.channel.on('message', listenerCallback);
+> cordova.channel.on("message", listenerCallback);
> ```
### cordova.channel.post(event, message)
-| Param | Type |
-| --- | --- |
-| event | string
|
+| Param | Type |
+| ------- | ------------------------------------------------------------------------------------------- |
+| event | `string` |
| message | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
Raises a user-defined event on the cordova side.
### cordova.channel.send(message)
-| Param | Type |
-| --- | --- |
+| Param | Type |
+| ------- | ------------------------------------------------------------------------------------------- |
| message | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
Raises a 'message' event on the cordova side.
@@ -153,29 +157,29 @@ It is an alias for `cordova.channel.post('message', message);`.
### cordova.app.on(event, callback)
-| Param | Type |
-| --- | --- |
-| event | string
|
-| callback | function
|
+| Param | Type |
+| -------- | ---------- |
+| event | `string` |
+| callback | `function` |
Registers callbacks for App events.
Currently supports the 'pause' and 'resume' events, which are raised automatically when the app switches to the background/foreground.
```js
-cordova.app.on('pause', (pauseLock) => {
- console.log('[node] app paused.');
+cordova.app.on("pause", (pauseLock) => {
+ console.log("[node] app paused.");
pauseLock.release();
});
-cordova.app.on('resume', () => {
- console.log('[node] app resumed.');
+cordova.app.on("resume", () => {
+ console.log("[node] app resumed.");
});
```
The 'pause' event is raised when the application switches to the background. On iOS, the system will wait for the 'pause' event handlers to return before finally suspending the application. For the purpose of letting the iOS application know when it can safely suspend after going to the background, a `pauseLock` argument is passed to each 'pause' listener, so that `release()` can be called on it to signal that listener has finished doing all the work it needed to do. The application will only suspend after all the locks have been released (or iOS forces it to).
```js
-cordova.app.on('pause', (pauseLock) => {
- server.close( () => {
+cordova.app.on("pause", (pauseLock) => {
+ server.close(() => {
// App will only suspend after the server stops listening for connections and current connections are closed.
pauseLock.release();
});
@@ -188,11 +192,11 @@ cordova.app.on('pause', (pauseLock) => {
Returns a writable path used for persistent data storage in the application. Its value corresponds to `NSDocumentDirectory` on iOS and `FilesDir` on Android.
-
-### Channel callback: function(arg)
-| Name | Type |
-| --- | --- |
-| arg | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
+### Channel callback: `function(arg)`
+
+| Name | Type |
+| ---- | ------------------------------------------------------------------------------------------- |
+| arg | any JS type that can be serialized with `JSON.stringify` and deserialized with `JSON.parse` |
The messages sent through the channel can be of any type that can be correctly serialized with [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp) on one side and deserialized with [`JSON.parse`](https://www.w3schools.com/js/js_json_parse.asp) on the other side, as it is what the channel does internally. This means that passing JS dates through the channel will convert them to strings and functions will be removed from their containing objects. In line with [The JSON Data Interchange Syntax Standard](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf), the channel supports sending messages that are composed of these JS types: `Boolean`, `Number`, `String`, `Object`, `Array`.
@@ -208,106 +212,132 @@ The Android OS doesn't define a temporary directory for the system or applicatio
This shows how to build an iOS app that exchanges text messages between the Cordova layer and the Node.js layer.
In macOS, using `Terminal`:
+
```bash
-$ cordova create HelloCordova
-$ cd HelloCordova
-$ cordova platform add ios
-$ cordova plugin add nodejs-mobile-cordova
-$ cordova plugin add cordova-plugin-console
+% cordova create HelloCordova
+% cd HelloCordova
+% cordova platform add ios
+% cordova plugin add nodejs-mobile-cordova
+% cordova plugin add cordova-plugin-console
```
+
You can either manually create the `./www/nodejs-project/` folder, the `./www/nodejs-project/main.js` file and edit `./www/js/index.js` or use the provided helper script to do it automatically. The helper script copies a more extended sample compared to the one provided with the manual steps.
---
-#### Set up project files using the helper script
+
+### Set up project files using the helper script
+
If you choose to use the helper script, you will be asked to overwrite the existing `./www/js/index.js` file:
+
```bash
-$ ./plugins/nodejs-mobile-cordova/install/sample-project/copy-sample-project.sh
-$ overwrite www/js/index.js? (y/n [n]) y
+./plugins/@red-mobile/nodejs-mobile-cordova/install/sample-project/copy-sample-project.sh
+overwrite www/js/index.js? (y/n [n]) y
```
+
The script creates the `./www/nodejs-project/` folder and adds two files:
- - `./www/nodejs-project/main.js`
- - `./www/nodejs-project/package.json`
+
+- `./www/nodejs-project/main.js`
+- `./www/nodejs-project/package.json`
The changes in `./www/js/index.js` are needed to invoke Node.js for Mobile Apps from Cordova.
---
-#### Set up project files using the manual steps
+
+### Set up project files using the manual steps
+
If you want to set up the project manually, first create the project folder for the Node.js files:
+
```bash
-$ mkdir www/nodejs-project
+% mkdir www/nodejs-project
```
+
Then, with your editor of choice (we use VS Code in this example) create the `main.js` script file:
+
```bash
-$ code www/nodejs-project/main.js
+% code www/nodejs-project/main.js
```
+
Add the following code to `main.js` and save the file:
+
```js
-const cordova = require('cordova-bridge');
+const cordova = require("cordova-bridge");
-cordova.channel.on('message', function (msg) {
- console.log('[node] received:', msg);
- cordova.channel.send('Replying to this message: ' + msg);
+cordova.channel.on("message", function (msg) {
+ console.log("[node] received:", msg);
+ cordova.channel.send("Replying to this message: " + msg);
});
```
+
Edit the cordova script file `www/js/index.js`:
+
+```bash
+% code `./www/js/index.js`
```
-$ code `./www/js/index.js`
-```
+
Append the following code at the end of the file:
+
```js
function channelListener(msg) {
- console.log('[cordova] received:' + msg);
+ console.log("[cordova] received:" + msg);
}
function startupCallback(err) {
- if (err) {
- console.log(err);
- } else {
- console.log ('Node.js Mobile Engine Started');
- nodejs.channel.send('Hello from Cordova!');
- }
-};
+ if (err) {
+ console.log(err);
+ } else {
+ console.log("Node.js Mobile Engine Started");
+ nodejs.channel.send("Hello from Cordova!");
+ }
+}
function startNodeProject() {
- nodejs.channel.setListener(channelListener);
- nodejs.start('main.js', startupCallback);
- // To disable the stdout/stderr redirection to the Android logcat:
- // nodejs.start('main.js', startupCallback, { redirectOutputToLogcat: false });
-};
-
+ nodejs.channel.setListener(channelListener);
+ nodejs.start("main.js", startupCallback);
+ // To disable the stdout/stderr redirection to the Android logcat:
+ // nodejs.start('main.js', startupCallback, { redirectOutputToLogcat: false });
+}
```
Search for the `onDeviceReady` event and in the event handler add a call to `startNodeProject()`:
+
```js
onDeviceReady: function() {
this.receivedEvent('deviceready');
startNodeProject();
},
```
+
Save the changes to the `www/js/index.js` file to complete the manual steps of setting up the project files.
---
After the project files have been created, either manually or using the helper script, open the Cordova app project in Xcode:
+
```bash
-$ open platforms/ios/HelloCordova.xcodeproj
+% open platforms/ios/HelloCordova.xcodeproj
```
+
Switch to Xcode:
- * select HelloCordova to view the project settings
- * in the `General` settings:
- * in the `Signing` section select a team to sign the app
- * in `Deployment Info` section select `Deployment Target` `11.0` or higher
+
+- select HelloCordova to view the project settings
+- in the `General` settings:
+ - in the `Signing` section select a team to sign the app
+ - in `Deployment Info` section select `Deployment Target` `11.0` or higher
Go back to `Terminal` to build the Cordova app
+
```bash
-$ cordova build ios --device
+% cordova build ios --device
```
+
Switch to Xcode:
- * select a target device for the project
- * run the project
- * enlarge the `Console` area and scroll to the bottom
- If you created the project following the manual steps, the output will look like this:
+- select a target device for the project
+- run the project
+- enlarge the `Console` area and scroll to the bottom
+
+If you created the project following the manual steps, the output will look like this:
+
```bash
2017-10-02 18:49:18.606100+0200 HelloCordova[2182:1463518] Node.js Mobile Engine Started
[node] received: Hello from Cordova!
@@ -315,7 +345,8 @@ Switch to Xcode:
```
If you used the helper script, the output will look like this:
-```
+
+```bash
2018-02-26 09:18:21.178612+0100 HelloCordova[1089:957630] Node.js Mobile Engine started
2018-02-26 09:18:21.385605+0100 HelloCordova[1089:957630] [cordova] MESSAGE from Node: "main.js loaded"
2018-02-26 09:18:21.385760+0100 HelloCordova[1089:957630] [cordova] "STARTED" event received from Node
@@ -326,16 +357,18 @@ If you used the helper script, the output will look like this:
```
## Node Modules
+
Node modules can be added to the project using `npm`.
The Node modules have to be installed in the `./www/nodejs-project/` folder and a `package.json` file needs to be added to the folder.
If you used the helper script to install the sample project, the `package.json` file is already present and you can proceed adding the desired Node modules.
-If you don't know how to create the `package.json` file, just copy the sample one from `./plugins/nodejs-mobile-cordova/install/sample-project/www/nodejs-project/package.json`.
+If you don't know how to create the `package.json` file, just copy the sample one from `./plugins/@red-mobile/nodejs-mobile-cordova/install/sample-project/www/nodejs-project/package.json`.
Then proceed with the installation of the Node modules you want to add to your Node.js project:
-```
-$ cd www/nodejs-project/
-$ npm install module-name
+
+```bash
+% cd www/nodejs-project/
+% npm install module-name
```
Rebuild your Cordova project so that the newly added Node modules are added to the Cordova application.
@@ -352,22 +385,49 @@ The plugin automatically detects native modules in `./www/nodejs-project/` by se
Building native modules for Android can take a long time, since it depends on building a standalone NDK toolchain for each required architecture. The resulting `.node` binaries are then included in the final application in a separate asset path for each architecture and the correct one will be chosen at runtime.
-While the plugin tries to detect automatically the presence of native modules, there's a way to override this detection and turn the native modules build process on or off, by creating the `www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt` file and setting its contents to `1` or `0` respectively. E.g., from the root path of your project:
+While the plugin tries to detect automatically the presence of native modules, there's a way to override this detection and turn the native modules build process on or off, by creating the `www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt` file and setting its contents to `1` or `0` respectively. E.g., from the root path of your project:
+
```sh
echo "1" > www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt
cordova run android
```
+
```sh
echo "1" > www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt
cordova run ios
```
+#### Prebuilds
+
+The plugin also automatically detects the presence of prebuilt native modules, and **disables** compiling them on the fly. The prebuilds are detected as `.node` files in a specific path in the npm package:
+
+```
+nodejs-project/node_modules//prebuilds/-/.node
+```
+
+Notice `PLATFORM` and `ARCH`. The supported values are:
+
+- PLATFORM = `android`
+ - ARCH = `arm`
+ - ARCH = `arm64`
+ - ARCH = `x64`
+- PLATFORM = `ios`
+ - ARCH = `arm64`
+ - ARCH = `x64`
+
+Compilation will then be forcefully disabled by hacking the `` folder to delete its `binding.gyp` and modify its `package.json` such that node-gyp will ignore this module for compilation.
+
+If you are a maintainer of a native module and want to support prebuilds for nodejs-mobile, check out the CLI tool [prebuild-for-nodejs-mobile](https://github.com/nodejs-mobile/prebuild-for-nodejs-mobile/tree/master).
+
+The plugin also provides you a helper script [rebuild-native-modules.sh](install/helper-scripts/rebuild-native-modules.sh) that can be used to prebuild third-party modules and speedup apps built time.
+
## Troubleshooting
### Android
If the installed Android NDK version is `>= r18`, the following error can occur while building for Android:
-```
+
+```sh
FAILURE: Build failed with an exception.
* What went wrong:
@@ -380,16 +440,18 @@ This is caused by the Gradle version used by `cordova-android` version `6.x` not
The [cordova-android issue](https://github.com/apache/cordova-android/issues/504) mentions possible workarounds the user may take to get around this issue, including updating the gradle plugin used by your Android Project / using an older NDK.
To solve this issue while using Android NDK versions `>= r18` with cordova-android 6.x without having to update the project created by cordova, the recommended workaround would be to copy the `mips64el-linux-android-4.9` and `mipsel-linux-android-4.9` toolchains from an older release into your local NDK install or create a local link to other toolchains so that the Gradle internal checks pass, since these toolchains won't be used by Cordova. Here's one way to do this, assuming the `ANDROID_NDK_HOME` environment variable is set in your system:
-```
-cd $ANDROID_NDK_HOME/toolchains
-ln -s aarch64-linux-android-4.9 mips64el-linux-android
-ln -s arm-linux-androideabi-4.9 mipsel-linux-android
+
+```bash
+% cd $ANDROID_NDK_HOME/toolchains
+% ln -s aarch64-linux-android-4.9 mips64el-linux-android
+% ln -s arm-linux-androideabi-4.9 mipsel-linux-android
```
### iOS
When using `Xcode 10` with `cordova-ios` version `4.x`, the following error might occur when trying to build or run the application:
-```
+
+```sh
The executable was signed with invalid entitlements.
The entitlements specified in you Application's Code Signing Entitlements file are invalid, not permitted, or do not match those specified in you provisioning profile.
@@ -397,17 +459,21 @@ The entitlements specified in you Application's Code Signing Entitlements file a
This is caused by the new `Xcode 10` build system, as documented in this [cordova-ios issue](https://github.com/apache/cordova-ios/issues/407), including these recommended workarounds:
-* Including the `--buildFlag="-UseModernBuildSystem=0"` flag in the `build` and `run` commands:
-```
-cordova run ios --buildFlag='-UseModernBuildSystem=0'
-cordova build ios --buildFlag='-UseModernBuildSystem=0'
-```
-* Adding the flag under the iOS release or debug config when using a `build.json` config file:
-```
-"buildFlag": [
- "-UseModernBuildSystem=0"
-]
-```
-* Changing the build system to the "Legacy Build System" when building from the Xcode IDE:
+- Including the `--buildFlag="-UseModernBuildSystem=0"` flag in the `build` and `run` commands:
+
+ ```bash
+ % cordova run ios --buildFlag='-UseModernBuildSystem=0'
+ % cordova build ios --buildFlag='-UseModernBuildSystem=0'
+ ```
+
+- Adding the flag under the iOS release or debug config when using a `build.json` config file:
+
+ ```json
+ "buildFlag": [
+ "-UseModernBuildSystem=0"
+ ]
+ ```
+
+- Changing the build system to the "Legacy Build System" when building from the Xcode IDE:
1. In the Xcode "File Menu", select "Project Settings...";
1. In the "Project Settings..." window, inside the "Per-User Project Settings:" area, change the "Build System:" setting to "Legacy Build System".
diff --git a/install/helper-scripts/ios-build-native-modules.sh b/install/helper-scripts/ios-build-native-modules.sh
new file mode 100644
index 0000000..f8ea2bc
--- /dev/null
+++ b/install/helper-scripts/ios-build-native-modules.sh
@@ -0,0 +1,125 @@
+#!/bin/zsh
+
+set -e
+
+# On M1 macs homebrew is located outside /usr/local/bin
+if [[ ! $PATH =~ /opt/homebrew/bin: ]]; then
+ PATH="/opt/homebrew/bin/:/opt/homebrew/sbin:$PATH"
+fi
+# Xcode executes script build phases in independant shell environment.
+# Force load users configuration file
+[ -f "$ZDOTDIR"/.zshrc ] && source "$ZDOTDIR"/.zshrc
+
+NODEPROJ="$CODESIGNING_FOLDER_PATH/www/nodejs-project/"
+
+if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
+# If build native modules preference is not set, look for it in the project's
+# www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt
+ PREFERENCE_FILE_PATH="$CODESIGNING_FOLDER_PATH/www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt"
+ if [ -f "$PREFERENCE_FILE_PATH" ]; then
+ NODEJS_MOBILE_BUILD_NATIVE_MODULES="$(cat $PREFERENCE_FILE_PATH | xargs)"
+ fi
+fi
+if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
+# If build native modules preference is not set, try to find .gyp files
+#to turn it on.
+ gypfiles=($(find "$NODEPROJ" -type f -name "*.gyp"))
+ if [ ${#gypfiles[@]} -gt 0 ]; then
+ NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
+ else
+ NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
+ fi
+fi
+
+if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
+
+# Delete object files that may already come from within the npm package.
+find "$NODEPROJ" -name "*.o" -type f -delete
+find "$NODEPROJ" -name "*.a" -type f -delete
+
+# Function to skip compilation of a prebuilt module
+preparePrebuiltModule()
+{
+ local DOT_NODE_PATH="$1"
+ local DOT_NODE_FULL="$(cd "$(dirname -- "$DOT_NODE_PATH")" >/dev/null; pwd -P)/$(basename -- "$DOT_NODE_PATH")"
+ local MODULE_ROOT="$(cd $DOT_NODE_PATH && cd .. && cd .. && cd .. && pwd)"
+ local MODULE_NAME="$(basename $MODULE_ROOT)"
+ echo "Preparing to use the prebuild in $MODULE_NAME"
+ # Move the prebuild to the correct folder:
+ rm -rf $MODULE_ROOT/build
+ mkdir -p $MODULE_ROOT/build/Release
+ mv $DOT_NODE_FULL $MODULE_ROOT/build/Release/
+ # Hack the npm package to forcefully disable compile-on-install:
+ rm -rf $MODULE_ROOT/binding.gyp
+ sed -i.bak 's/"install"/"dontinstall"/g; s/"rebuild"/"dontrebuild"/g; s/"gypfile"/"dontgypfile"/g' $MODULE_ROOT/package.json
+}
+
+# Delete bundle contents that may be there from previous builds.
+# Handle the special case where the module has a prebuild that we want to use
+if [[ "$PLATFORM_PREFERRED_ARCH" == "arm64" ]]; then
+ PREBUILD_ARCH="arm64"
+else
+ PREBUILD_ARCH="x64"
+fi
+if [[ "$PLATFORM_NAME" == "iphonesimulator" ]] && [[ "$NATIVE_ARCH" == "arm64" ]]; then
+ SUFFIX="-simulator"
+ PREBUILD_ARCH="arm64"
+else
+ SUFFIX=""
+fi
+find -E "$NODEPROJ" \
+ ! -regex ".*/prebuilds/ios-$PREBUILD_ARCH$SUFFIX" \
+ -regex '.*/prebuilds/[^/]*$' -type d \
+ -prune -exec rm -rf "{}" \;
+find -E "$NODEPROJ" \
+ ! -regex ".*/prebuilds/ios-$PREBUILD_ARCH$SUFFIX/.*\.node$" \
+ -name '*.node' -type f \
+ -exec rm "{}" \;
+find "$NODEPROJ" \
+ -name "*.framework" -type d \
+ -prune -exec rm -rf "{}" \;
+for DOT_NODE in `find -E "$NODEPROJ" -regex ".*/prebuilds/ios-$PREBUILD_ARCH$SUFFIX/.*\.node$" -type d`; do
+ preparePrebuiltModule "$DOT_NODE"
+done
+
+# Symlinks to binaries are resolved by cordova prepare during the copy, causing build time errors.
+# The original project's .bin folder will be added to the path before building the native modules.
+find "$NODEPROJ" -path "*/.bin/*" -delete
+find "$NODEPROJ" -name ".bin" -type d -delete
+# Get the nodejs-mobile-gyp location
+if [ -d "$PROJECT_DIR/../../plugins/@red-mobile/nodejs-mobile-cordova/node_modules/nodejs-mobile-gyp/" ]; then
+NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../../plugins/@red-mobile/nodejs-mobile-cordova/node_modules/nodejs-mobile-gyp/ && pwd )"
+else
+NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../../node_modules/nodejs-mobile-gyp/ && pwd )"
+fi
+NODEJS_MOBILE_GYP_BIN_FILE="$NODEJS_MOBILE_GYP_DIR"/bin/node-gyp.js
+# Rebuild modules with right environment
+NODEJS_HEADERS_DIR="$( cd "$( dirname "$PRODUCT_SETTINGS_PATH" )" && cd Plugins/@red-mobile/nodejs-mobile-cordova/ && pwd )"
+# Adds the original project .bin to the path. It's a workaround
+# to correctly build some modules that depend on symlinked modules,
+# like node-pre-gyp.
+if [ -d "$PROJECT_DIR/../../www/nodejs-project/node_modules/.bin/" ]; then
+ PATH="$PROJECT_DIR/../../www/nodejs-project/node_modules/.bin/:$PATH"
+fi
+
+pushd $NODEPROJ
+export GYP_DEFINES="OS=ios"
+export npm_config_nodedir="$NODEJS_HEADERS_DIR"
+export npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE"
+export npm_config_format="make-ios"
+export npm_config_node_engine="chakracore"
+export NODEJS_MOBILE_GYP="$NODEJS_MOBILE_GYP_BIN_FILE"
+export npm_config_platform="ios"
+
+if [[ "$PLATFORM_NAME" == "iphoneos" ]]; then
+ export npm_config_arch="arm64"
+else
+ if [[ "$HOST_ARCH" == "arm64" ]] ; then # M1 mac
+ export GYP_DEFINES="OS=ios iossim=true"
+ export npm_config_arch="arm64"
+ else
+ export npm_config_arch="x64"
+ fi
+fi
+npm --verbose rebuild --build-from-source
+popd
\ No newline at end of file
diff --git a/install/helper-scripts/ios-sign-native-modules.sh b/install/helper-scripts/ios-sign-native-modules.sh
new file mode 100644
index 0000000..4487c1a
--- /dev/null
+++ b/install/helper-scripts/ios-sign-native-modules.sh
@@ -0,0 +1,33 @@
+#!/bin/zsh
+
+set -e
+
+# On M1 macs homebrew is located outside /usr/local/bin
+if [[ ! $PATH =~ /opt/homebrew/bin: ]]; then
+ PATH="/opt/homebrew/bin/:/opt/homebrew/sbin:$PATH"
+fi
+# Xcode executes script build phases in independant shell environment.
+# Force load users configuration file
+[ -f "$ZDOTDIR"/.zshrc ] && source "$ZDOTDIR"/.zshrc
+
+# Delete object files
+find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.o" -type f -delete
+find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.a" -type f -delete
+
+# Create Info.plist for each framework built and loader override.
+PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../../Plugins/@red-mobile/nodejs-mobile-cordova/install/helper-scripts/ && pwd )"
+NODEJS_PROJECT_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd www/nodejs-project && pwd )"
+node "$PATCH_SCRIPT_DIR"/ios-create-plists-and-dlopen-override.js $NODEJS_PROJECT_DIR
+# Embed every resulting .framework in the application and delete them afterwards.
+embed_framework()
+{
+ FRAMEWORK_NAME="$(basename "$1")"
+ mkdir -p "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"
+ cp -r "$1" "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"
+ /usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/$FRAMEWORK_NAME"
+}
+find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.framework" -type d | while read frmwrk_path; do embed_framework "$frmwrk_path"; done
+
+#Delete gyp temporary .deps dependency folders from the project structure.
+find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/.deps/*" -delete
+find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name ".deps" -type d -delete
\ No newline at end of file
diff --git a/install/helper-scripts/rebuild-native-modules.sh b/install/helper-scripts/rebuild-native-modules.sh
new file mode 100644
index 0000000..9d2bbe2
--- /dev/null
+++ b/install/helper-scripts/rebuild-native-modules.sh
@@ -0,0 +1,35 @@
+#!/bin/zsh
+
+# Delete object files that may already come from within the npm package.
+find "nodejs-project" -name "*.o" -type f -delete
+find "nodejs-project" -name "*.a" -type f -delete
+find "nodejs-project" -name "*.node" -type f -delete
+
+# Delete bundle contents that may be there from previous builds.
+find "nodejs-project" -path "*/*.node/*" -delete
+find "nodejs-project" -name "*.node" -type d -delete
+
+NATIVE_MODULES=($(find "nodejs-project" -type f -name "binding.gyp" | sed -E 's|/[^/]+$||' | sort -u))
+
+echo "Found ${#NATIVE_MODULES[@]} native modules"
+
+for module in "${NATIVE_MODULES[@]}"
+do
+ pushd "$module"
+ echo "Building $(basename $module) for iOS devices"
+ npx prebuild-for-nodejs-mobile ios-arm64
+ echo "Building $(basename $module) for iOS simulator"
+ if [[ $(uname -m) == 'arm64' ]] # if M1 mac
+ then
+ npx prebuild-for-nodejs-mobile ios-arm64-simulator
+ else
+ npx prebuild-for-nodejs-mobile ios-x64-simulator
+ fi
+ echo "Building $(basename $module) for Android arm64"
+ npx prebuild-for-nodejs-mobile android-arm64
+ echo "Building $(basename $module) for Android arm"
+ npx prebuild-for-nodejs-mobile android-arm
+ echo "Building $(basename $module) for Android x86"
+ npx prebuild-for-nodejs-mobile android-x64
+ popd
+done
diff --git a/install/hooks/android/after-prepare-create-macOS-builder-helper.js b/install/hooks/android/after-prepare-create-macOS-builder-helper.js
index 91eda52..ec8d5e5 100644
--- a/install/hooks/android/after-prepare-create-macOS-builder-helper.js
+++ b/install/hooks/android/after-prepare-create-macOS-builder-helper.js
@@ -14,6 +14,7 @@ function getPlatformWWWPath(context, platform) {
return platformAPIInstance.locations.www;
}
+
// Adds a helper script to run "npm rebuild" with the current PATH.
// This workaround is needed for Android Studio on macOS when it is not started
// from the command line, as npm probably won't be in the PATH at build time.
diff --git a/install/hooks/android/before-plugin-install.js b/install/hooks/android/before-plugin-install.js
index e720d6d..958350f 100644
--- a/install/hooks/android/before-plugin-install.js
+++ b/install/hooks/android/before-plugin-install.js
@@ -2,9 +2,8 @@ var fs = require('fs');
var zlib = require('zlib');
const nodeProjectFolder = 'www/nodejs-project';
-const libFolderPath = 'plugins/nodejs-mobile-cordova/libs/android/libnode/bin/';
+const libFolderPath = 'plugins/@red-mobile/nodejs-mobile-cordova/libs/android/libnode/bin/';
const path_armv7 = libFolderPath + 'armeabi-v7a/';
-const path_x86 = libFolderPath + 'x86/'
const path_arm64 = libFolderPath + 'arm64-v8a/';
const path_x64 = libFolderPath + 'x86_64/'
const lib_name = 'libnode.so';
@@ -27,11 +26,9 @@ function unzip(libFolderPath, callback) {
function unzipAll(callback) {
unzip(path_armv7, function() {
- unzip(path_x86, function() {
- unzip(path_arm64, function() {
- unzip(path_x64, function() {
- callback(null);
- });
+ unzip(path_arm64, function() {
+ unzip(path_x64, function() {
+ callback(null);
});
});
});
diff --git a/install/hooks/both/after-plugin-install-copy-helper-scripts.js b/install/hooks/both/after-plugin-install-copy-helper-scripts.js
new file mode 100644
index 0000000..da18c0a
--- /dev/null
+++ b/install/hooks/both/after-plugin-install-copy-helper-scripts.js
@@ -0,0 +1,10 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = function(context)
+{
+ fs.copyFileSync(
+ path.join(context.opts.plugin.dir, "install/helper-scripts/rebuild-native-modules.sh"),
+ path.join(context.opts.projectRoot, "rebuild-native-modules.sh")
+ )
+}
diff --git a/install/hooks/both/after-prepare-patch-npm-packages.js b/install/hooks/both/after-prepare-patch-npm-packages.js
index a7eacd3..7b19270 100644
--- a/install/hooks/both/after-prepare-patch-npm-packages.js
+++ b/install/hooks/both/after-prepare-patch-npm-packages.js
@@ -1,49 +1,75 @@
-const fs = require('fs');
-const path = require('path');
+const fs = require("fs");
+const path = require("path");
+
+function getBinaryPathConfiguration(binaryPathConfiguration) {
+ return binaryPathConfiguration
+ .replace(/\{node_abi\}/g, "node_abi")
+ .replace(/\{platform\}/g, "platform")
+ .replace(/\{arch\}/g, "arch")
+ .replace(/\{target_arch\}/g, "target_arch")
+ .replace(/\{libc\}/g, "libc");
+}
// Patches a package.json in case it has variable substitution for
// the module's binary at runtime. Since we are cross-compiling
// for mobile, this substitution will have different values at
// build time and runtime, so we pre-substitute them with fixed
// values.
-function patchPackageJSON_preNodeGyp_modulePath(filePath)
-{
+function patchPackageJSON_preNodeGyp_modulePath(filePath) {
let packageReadData = fs.readFileSync(filePath);
let packageJSON = JSON.parse(packageReadData);
- if ( packageJSON && packageJSON.binary && packageJSON.binary.module_path ) {
- let binaryPathConfiguration = packageJSON.binary.module_path;
- binaryPathConfiguration = binaryPathConfiguration.replace(/\{node_abi\}/g, "node_abi");
- binaryPathConfiguration = binaryPathConfiguration.replace(/\{platform\}/g, "platform");
- binaryPathConfiguration = binaryPathConfiguration.replace(/\{arch\}/g, "arch");
- binaryPathConfiguration = binaryPathConfiguration.replace(/\{target_arch\}/g, "target_arch");
- binaryPathConfiguration = binaryPathConfiguration.replace(/\{libc\}/g, "libc");
+ if (packageJSON?.binary?.module_path) {
+ const binaryPathConfiguration = getBinaryPathConfiguration(
+ packageJSON.binary.module_path
+ );
packageJSON.binary.module_path = binaryPathConfiguration;
- let packageWriteData = JSON.stringify(packageJSON, null, 2);
+ const packageWriteData = JSON.stringify(packageJSON, null, 2);
fs.writeFileSync(filePath, packageWriteData);
}
}
+/**
+ * Since npm 7+, the environment variable npm_config_node_gyp (which we rely on
+ * in scripts/ios-build-native-modules.sh) has not been forwarded to package
+ * scripts, so here we patch each module's package.json to replace
+ * node-gyp-build with our fork, node-gyp-build-mobile. This fork reads a
+ * different environment variable, originally created in
+ * scripts/ios-build-native-modules.sh, pointing to node-mobile-gyp.
+ */
+function patchPackageJSONNodeGypBuild(packageJSONPath) {
+ try {
+ const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath));
+ if (packageJSON?.scripts?.install?.includes("node-gyp-build")) {
+ packageJSON.scripts.install = packageJSON.scripts.install.replace(
+ /node-gyp-build(?!-)/g,
+ "$PROJECT_DIR/../node_modules/.bin/node-gyp-build-mobile"
+ );
+ fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2));
+ }
+ } catch (error) {
+ console.error(`Failed to patch ${packageJSONPath}:`, error);
+ }
+}
+
// Visits every package.json to apply patches.
-function visitPackageJSON(folderPath)
-{
+function visitPackageJSON(folderPath) {
let files = fs.readdirSync(folderPath);
- for (var i in files) {
+ for (let i in files) {
let name = files[i];
let filePath = path.join(folderPath, files[i]);
- if(fs.statSync(filePath).isDirectory()) {
+ if (fs.lstatSync(filePath).isDirectory()) {
visitPackageJSON(filePath);
- } else {
- if (name === 'package.json') {
- try {
- patchPackageJSON_preNodeGyp_modulePath(filePath);
- } catch (e) {
- console.warn(
- 'Failed to patch the file : "' +
+ } else if (name === "package.json") {
+ try {
+ patchPackageJSON_preNodeGyp_modulePath(filePath);
+ patchPackageJSONNodeGypBuild(filePath);
+ } catch (e) {
+ console.warn(
+ 'Failed to patch the file : "' +
filePath +
'". The following error was thrown: ' +
JSON.stringify(e)
- );
- }
+ );
}
}
}
@@ -51,8 +77,12 @@ function visitPackageJSON(folderPath)
// Applies the patch to the selected platform
function patchTargetPlatform(context, platform) {
- const platformPath = path.join(context.opts.projectRoot, 'platforms', platform);
- const platformAPI = require(path.join(platformPath, 'cordova', 'Api'));
+ const platformPath = path.join(
+ context.opts.projectRoot,
+ "platforms",
+ platform
+ );
+ const platformAPI = require(path.join(platformPath, "cordova", "Api"));
let platformAPIInstance;
try {
platformAPIInstance = new platformAPI();
@@ -60,18 +90,21 @@ function patchTargetPlatform(context, platform) {
platformAPIInstance = new platformAPI(platform, platformPath);
}
const wwwPath = platformAPIInstance.locations.www;
- const nodeModulesPathToPatch = path.join(wwwPath, 'nodejs-project', 'node_modules');
+ const nodeModulesPathToPatch = path.join(
+ wwwPath,
+ "nodejs-project",
+ "node_modules"
+ );
if (fs.existsSync(nodeModulesPathToPatch)) {
visitPackageJSON(nodeModulesPathToPatch);
}
}
-module.exports = function(context)
-{
- if (context.opts.platforms.indexOf('android') >= 0) {
- patchTargetPlatform(context, 'android');
+module.exports = function (context) {
+ if (context.opts.platforms.indexOf("android") >= 0) {
+ patchTargetPlatform(context, "android");
}
- if (context.opts.platforms.indexOf('ios') >= 0) {
- patchTargetPlatform(context, 'ios');
+ if (context.opts.platforms.indexOf("ios") >= 0) {
+ patchTargetPlatform(context, "ios");
}
-}
+};
diff --git a/install/hooks/ios/after-plugin-install.js b/install/hooks/ios/after-plugin-install.js
index dbd23df..3f347a4 100644
--- a/install/hooks/ios/after-plugin-install.js
+++ b/install/hooks/ios/after-plugin-install.js
@@ -7,7 +7,7 @@ module.exports = function(context) {
// Require the iOS platform Api to get the Xcode .pbxproj path.
var iosPlatformPath = path.join(context.opts.projectRoot, 'platforms', 'ios');
var iosAPI = require(path.join(iosPlatformPath, 'cordova', 'Api'));
- var iosAPIInstance = new iosAPI();
+ var iosAPIInstance = new iosAPI('ios', iosPlatformPath);
var pbxprojPath = iosAPIInstance.locations.pbxproj;
// Read the Xcode project and get the target.
@@ -17,64 +17,7 @@ module.exports = function(context) {
// Adds a build phase to rebuild native modules.
var rebuildNativeModulesBuildPhaseName = 'Build Node.js Mobile Native Modules';
- var rebuildNativeModulesBuildPhaseScript = `
-set -e
-if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
-# If build native modules preference is not set, look for it in the project's
-# www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt
- PREFERENCE_FILE_PATH="$CODESIGNING_FOLDER_PATH/www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt"
- if [ -f "$PREFERENCE_FILE_PATH" ]; then
- NODEJS_MOBILE_BUILD_NATIVE_MODULES="$(cat $PREFERENCE_FILE_PATH | xargs)"
- fi
-fi
-if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
-# If build native modules preference is not set, try to find .gyp files
-#to turn it on.
- gypfiles=($(find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -type f -name "*.gyp"))
- if [ \${#gypfiles[@]} -gt 0 ]; then
- NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
- else
- NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
- fi
-fi
-if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
-# Delete object files that may already come from within the npm package.
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.o" -type f -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.a" -type f -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.node" -type f -delete
-# Delete bundle contents that may be there from previous builds.
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/*.node/*" -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.node" -type d -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/*.framework/*" -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.framework" -type d -delete
-# Symlinks to binaries are resolved by cordova prepare during the copy, causing build time errors.
-# The original project's .bin folder will be added to the path before building the native modules.
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/.bin/*" -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name ".bin" -type d -delete
-# Get the nodejs-mobile-gyp location
-if [ -d "$PROJECT_DIR/../../plugins/nodejs-mobile-cordova/node_modules/nodejs-mobile-gyp/" ]; then
-NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../../plugins/nodejs-mobile-cordova/node_modules/nodejs-mobile-gyp/ && pwd )"
-else
-NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../../node_modules/nodejs-mobile-gyp/ && pwd )"
-fi
-NODEJS_MOBILE_GYP_BIN_FILE="$NODEJS_MOBILE_GYP_DIR"/bin/node-gyp.js
-# Rebuild modules with right environment
-NODEJS_HEADERS_DIR="$( cd "$( dirname "$PRODUCT_SETTINGS_PATH" )" && cd Plugins/nodejs-mobile-cordova/ && pwd )"
-# Adds the original project .bin to the path. It's a workaround
-# to correctly build some modules that depend on symlinked modules,
-# like node-pre-gyp.
-if [ -d "$PROJECT_DIR/../../www/nodejs-project/node_modules/.bin/" ]; then
- PATH="$PROJECT_DIR/../../www/nodejs-project/node_modules/.bin/:$PATH"
-fi
-pushd $CODESIGNING_FOLDER_PATH/www/nodejs-project/
-if [ "$PLATFORM_NAME" == "iphoneos" ]
-then
-GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="arm64" npm --verbose rebuild --build-from-source
-else
-GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="x64" npm --verbose rebuild --build-from-source
-fi
-popd
-`
+ var rebuildNativeModulesBuildPhaseScript = 'zsh "$PROJECT_DIR/../../plugins/@red-mobile/nodejs-mobile-cordova/install/helper-scripts/ios-build-native-modules.sh"'
var rebuildNativeModulesBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', rebuildNativeModulesBuildPhaseName, firstTargetUUID);
if (!(rebuildNativeModulesBuildPhase)) {
xcodeProject.addBuildPhase(
@@ -82,60 +25,13 @@ popd
'PBXShellScriptBuildPhase',
rebuildNativeModulesBuildPhaseName,
firstTargetUUID,
- { shellPath: '/bin/sh', shellScript: rebuildNativeModulesBuildPhaseScript }
+ { shellPath: '/bin/zsh', shellScript: rebuildNativeModulesBuildPhaseScript }
);
}
// Adds a build phase to sign native modules.
var signNativeModulesBuildPhaseName = 'Sign Node.js Mobile Native Modules';
- var signNativeModulesBuildPhaseScript = `
-set -e
-if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
-# If build native modules preference is not set, look for it in the project's
-# www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt
- PREFERENCE_FILE_PATH="$CODESIGNING_FOLDER_PATH/www/NODEJS_MOBILE_BUILD_NATIVE_MODULES_VALUE.txt"
- if [ -f "$PREFERENCE_FILE_PATH" ]; then
- NODEJS_MOBILE_BUILD_NATIVE_MODULES="$(cat $PREFERENCE_FILE_PATH | xargs)"
- # Remove the preference file so it doesn't get in the application package.
- rm "$PREFERENCE_FILE_PATH"
- fi
-fi
-if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
-# If build native modules preference is not set, try to find .gyp files
-#to turn it on.
- gypfiles=($(find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -type f -name "*.gyp"))
- if [ \${#gypfiles[@]} -gt 0 ]; then
- NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
- else
- NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
- fi
-fi
-if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
-# Delete object files
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.o" -type f -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.a" -type f -delete
-# Create Info.plist for each framework built and loader override.
-PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../../Plugins/nodejs-mobile-cordova/install/helper-scripts/ && pwd )"
-NODEJS_PROJECT_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd www/nodejs-project/ && pwd )"
-node "$PATCH_SCRIPT_DIR"/ios-create-plists-and-dlopen-override.js $NODEJS_PROJECT_DIR
-# Embed every resulting .framework in the application and delete them afterwards.
-embed_framework()
-{
- FRAMEWORK_NAME="$(basename "$1")"
- mkdir -p "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"
- cp -r "$1" "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"
- /usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/$FRAMEWORK_NAME"
-}
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.framework" -type d | while read frmwrk_path; do embed_framework "$frmwrk_path"; done
-
-#Delete gyp temporary .deps dependency folders from the project structure.
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/.deps/*" -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name ".deps" -type d -delete
-
-#Delete frameworks from their build paths
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -path "*/*.framework/*" -delete
-find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.framework" -type d -delete
-`
+ var signNativeModulesBuildPhaseScript = 'zsh "$PROJECT_DIR/../../plugins/@red-mobile/nodejs-mobile-cordova/install/helper-scripts/ios-sign-native-modules.sh"'
var signNativeModulesBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', signNativeModulesBuildPhaseName, firstTargetUUID);
if (!(signNativeModulesBuildPhase)) {
xcodeProject.addBuildPhase(
@@ -143,11 +39,10 @@ find "$CODESIGNING_FOLDER_PATH/www/nodejs-project/" -name "*.framework" -type d
'PBXShellScriptBuildPhase',
signNativeModulesBuildPhaseName,
firstTargetUUID,
- { shellPath: '/bin/sh', shellScript: signNativeModulesBuildPhaseScript }
+ { shellPath: '/bin/zsh', shellScript: signNativeModulesBuildPhaseScript }
);
}
// Write the changes into the Xcode project.
fs.writeFileSync(pbxprojPath, xcodeProject.writeSync());
-
}
diff --git a/install/hooks/ios/before-plugin-install.js b/install/hooks/ios/before-plugin-install.js
index bf9d705..14f4c7c 100644
--- a/install/hooks/ios/before-plugin-install.js
+++ b/install/hooks/ios/before-plugin-install.js
@@ -2,7 +2,7 @@ var fs = require('fs');
var targz2 = require('tar.gz2');
const nodeProjectFolder = 'www/nodejs-project';
-const nodeMobileFolderPath = 'plugins/nodejs-mobile-cordova/libs/ios/nodemobile/';
+const nodeMobileFolderPath = 'plugins/@red-mobile/nodejs-mobile-cordova/libs/ios/nodemobile/';
const nodeMobileFileName = 'NodeMobile.xcframework';
const nodeMobileFilePath = nodeMobileFolderPath + nodeMobileFileName;
const zipFileName = nodeMobileFileName + '.tar.zip';
diff --git a/install/hooks/ios/before-plugin-uninstall.js b/install/hooks/ios/before-plugin-uninstall.js
index 3b1d3f5..a950a2d 100644
--- a/install/hooks/ios/before-plugin-uninstall.js
+++ b/install/hooks/ios/before-plugin-uninstall.js
@@ -41,7 +41,7 @@ module.exports = function(context) {
// Require the iOS platform Api to get the Xcode .pbxproj path.
var iosPlatformPath = path.join(context.opts.projectRoot, 'platforms', 'ios');
var iosAPI = require(path.join(iosPlatformPath, 'cordova', 'Api'));
- var iosAPIInstance = new iosAPI();
+ var iosAPIInstance = new iosAPI('ios', iosPlatformPath);
var pbxprojPath = iosAPIInstance.locations.pbxproj;
// Read the Xcode project and get the target.
diff --git a/install/hooks/ios/fix-xcframework-path.js b/install/hooks/ios/fix-xcframework-path.js
index 98d43c0..6c0c097 100644
--- a/install/hooks/ios/fix-xcframework-path.js
+++ b/install/hooks/ios/fix-xcframework-path.js
@@ -5,11 +5,11 @@ module.exports = function(context) {
// Require the iOS platform Api to get the Xcode .pbxproj path.
var iosPlatformPath = path.join(context.opts.projectRoot, 'platforms', 'ios');
var iosAPI = require(path.join(iosPlatformPath, 'cordova', 'Api'));
- var iosAPIInstance = new iosAPI();
+ var iosAPIInstance = new iosAPI('ios', iosPlatformPath);
var pbxprojPath = iosAPIInstance.locations.pbxproj;
var rootIosProjDir = iosAPIInstance.locations.root;
var cordovaProjPath = iosAPIInstance.locations.xcodeCordovaProj;
- var xcFrameworkPath = path.join(cordovaProjPath, 'Plugins', 'nodejs-mobile-cordova', 'NodeMobile.xcframework');
+ var xcFrameworkPath = path.join(cordovaProjPath, 'Plugins', '@red-mobile', 'nodejs-mobile-cordova', 'NodeMobile.xcframework');
var relativeXcFrameworkPath = path.relative(rootIosProjDir, xcFrameworkPath);
// Patch the project file to fix a .xcframework include error.
diff --git a/install/nodejs-mobile-cordova-assets/builtin_modules/cordova-bridge/index.js b/install/nodejs-mobile-cordova-assets/builtin_modules/cordova-bridge/index.js
index 510717f..d50647f 100644
--- a/install/nodejs-mobile-cordova-assets/builtin_modules/cordova-bridge/index.js
+++ b/install/nodejs-mobile-cordova-assets/builtin_modules/cordova-bridge/index.js
@@ -1,51 +1,51 @@
-'use strict';
+"use strict";
-const EventEmitter = require('events');
-const NativeBridge = process._linkedBinding('cordova_bridge');
+const EventEmitter = require("events");
+const NativeBridge = process._linkedBinding("cordova_bridge");
/**
* Built-in events channel to exchange events between the Cordova app
* and the Node.js app. It allows to emit user defined event types with
* optional arguments.
*/
-const EVENT_CHANNEL = '_EVENTS_';
+const EVENT_CHANNEL = "_EVENTS_";
/**
* Built-in, one-way event channel reserved for sending events from
* the Cordova plug-in native layer to the Node.js app.
*/
-const SYSTEM_CHANNEL = '_SYSTEM_';
+const SYSTEM_CHANNEL = "_SYSTEM_";
/**
* This class is defined in www/nodejs-apis.js as well.
* Any change made here should be ported to www/nodejs-apis.js too.
* The MessageCodec class provides two static methods to serialize/deserialize
* the data sent through the events channel.
-*/
+ */
class MessageCodec {
// This is a 'private' constructor, should only be used by this class
// static methods.
constructor(_event, ..._payload) {
this.event = _event;
this.payload = JSON.stringify(_payload);
- };
+ }
// Serialize the message payload and the message.
static serialize(event, ...payload) {
const envelope = new MessageCodec(event, ...payload);
// Return the serialized message, that can be sent through a channel.
return JSON.stringify(envelope);
- };
+ }
// Deserialize the message and the message payload.
static deserialize(message) {
var envelope = JSON.parse(message);
- if (typeof envelope.payload !== 'undefined') {
+ if (typeof envelope.payload !== "undefined") {
envelope.payload = JSON.parse(envelope.payload);
}
return envelope;
- };
-};
+ }
+}
/**
* Channel super class.
@@ -60,15 +60,15 @@ class ChannelSuper extends EventEmitter {
// the event to Node.
this.emitLocal = this.emit;
delete this.emit;
- };
+ }
emitWrapper(type, ...msg) {
const _this = this;
- setImmediate( () => {
+ setImmediate(() => {
_this.emitLocal(type, ...msg);
- });
- };
-};
+ });
+ }
+}
/**
* Events channel class that supports user defined event types with
@@ -80,19 +80,19 @@ class ChannelSuper extends EventEmitter {
class EventChannel extends ChannelSuper {
post(event, ...msg) {
NativeBridge.sendMessage(this.name, MessageCodec.serialize(event, ...msg));
- };
+ }
// Posts a 'message' event, to be backward compatible with old code.
send(...msg) {
- this.post('message', ...msg);
- };
+ this.post("message", ...msg);
+ }
processData(data) {
// The data contains the serialized message envelope.
var envelope = MessageCodec.deserialize(data);
- this.emitWrapper(envelope.event, ...(envelope.payload));
- };
-};
+ this.emitWrapper(envelope.event, ...envelope.payload);
+ }
+}
/**
* System event Lock class
@@ -114,12 +114,11 @@ class SystemEventLock {
}
// Check if the lock can be released and release it.
_checkRelease() {
- if(this._locksAcquired<=0) {
- this._hasReleased=true;
+ if (this._locksAcquired <= 0) {
+ this._hasReleased = true;
this._callback();
}
}
-
}
/**
@@ -131,49 +130,49 @@ class SystemChannel extends ChannelSuper {
super(name);
// datadir should not change during runtime, so we cache it.
this._cacheDataDir = null;
- };
+ }
emitWrapper(type) {
// Overload the emitWrapper to handle the pause event locks.
const _this = this;
- if (type.startsWith('pause')) {
- setImmediate( () => {
- let releaseMessage = 'release-pause-event';
- let eventArguments = type.split('|');
+ if (type.startsWith("pause")) {
+ setImmediate(() => {
+ let releaseMessage = "release-pause-event";
+ let eventArguments = type.split("|");
if (eventArguments.length >= 2) {
// The expected format for the release message is "release-pause-event|{eventId}"
// eventId comes from the pause event, with the format "pause|{eventId}"
- releaseMessage = releaseMessage + '|' + eventArguments[1];
+ releaseMessage = releaseMessage + "|" + eventArguments[1];
}
// Create a lock to signal the native side after the app event has been handled.
let eventLock = new SystemEventLock(
() => {
NativeBridge.sendMessage(_this.name, releaseMessage);
- }
- , _this.listenerCount("pause") // A lock for each current event listener. All listeners need to call release().
+ },
+ _this.listenerCount("pause") // A lock for each current event listener. All listeners need to call release().
);
_this.emitLocal("pause", eventLock);
});
} else {
- setImmediate( () => {
+ setImmediate(() => {
_this.emitLocal(type);
});
}
- };
+ }
processData(data) {
// The data is the event.
this.emitWrapper(data);
- };
+ }
// Get a writable data directory for persistent file storage.
datadir() {
- if (this._cacheDataDir===null) {
- this._cacheDataDir=NativeBridge.getDataDir();
+ if (this._cacheDataDir === null) {
+ this._cacheDataDir = NativeBridge.getDataDir();
}
return this._cacheDataDir;
- };
-};
+ }
+}
/**
* Manage the registered channels to emit events/messages received by the
@@ -189,9 +188,9 @@ function bridgeListener(channelName, data) {
if (channels.hasOwnProperty(channelName)) {
channels[channelName].processData(data);
} else {
- console.error('ERROR: Channel not found:', channelName);
+ console.error("ERROR: Channel not found:", channelName);
}
-};
+}
/*
* The bridge's native code processes each channel's messages in a dedicated
@@ -201,7 +200,7 @@ function bridgeListener(channelName, data) {
function registerChannel(channel) {
channels[channel.name] = channel;
NativeBridge.registerChannel(channel.name, bridgeListener);
-};
+}
/**
* Module exports.
@@ -217,5 +216,5 @@ registerChannel(eventChannel);
module.exports = exports = {
app: systemChannel,
- channel: eventChannel
+ channel: eventChannel,
};
diff --git a/install/sample-project/copy-sample-project.sh b/install/sample-project/copy-sample-project.sh
index 075de21..2e44793 100755
--- a/install/sample-project/copy-sample-project.sh
+++ b/install/sample-project/copy-sample-project.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-SRC_PATH="plugins/nodejs-mobile-cordova/install/sample-project"
+SRC_PATH="plugins/@red-mobile/nodejs-mobile-cordova/install/sample-project"
copySampleFile () {
cp -i "$SRC_PATH/$1" $1
@@ -9,4 +9,4 @@ mkdir -p "www/nodejs-project"
copySampleFile "www/js/index.js"
copySampleFile "www/nodejs-project/main.js"
-copySampleFile "www/nodejs-project/package.json"
\ No newline at end of file
+copySampleFile "www/nodejs-project/package.json"
diff --git a/libs/android/libnode/bin/arm64-v8a/libnode.so.gz b/libs/android/libnode/bin/arm64-v8a/libnode.so.gz
index f58a44c..2b29c14 100644
Binary files a/libs/android/libnode/bin/arm64-v8a/libnode.so.gz and b/libs/android/libnode/bin/arm64-v8a/libnode.so.gz differ
diff --git a/libs/android/libnode/bin/armeabi-v7a/libnode.so.gz b/libs/android/libnode/bin/armeabi-v7a/libnode.so.gz
index 3c28124..f82944d 100644
Binary files a/libs/android/libnode/bin/armeabi-v7a/libnode.so.gz and b/libs/android/libnode/bin/armeabi-v7a/libnode.so.gz differ
diff --git a/libs/android/libnode/bin/x86/libnode.so.gz b/libs/android/libnode/bin/x86/libnode.so.gz
deleted file mode 100644
index df789bd..0000000
Binary files a/libs/android/libnode/bin/x86/libnode.so.gz and /dev/null differ
diff --git a/libs/android/libnode/bin/x86_64/libnode.so.gz b/libs/android/libnode/bin/x86_64/libnode.so.gz
index 7e65ae7..fba624e 100644
Binary files a/libs/android/libnode/bin/x86_64/libnode.so.gz and b/libs/android/libnode/bin/x86_64/libnode.so.gz differ
diff --git a/libs/android/libnode/include/node/common.gypi b/libs/android/libnode/include/node/common.gypi
index 84be79f..ade3b21 100644
--- a/libs/android/libnode/include/node/common.gypi
+++ b/libs/android/libnode/include/node/common.gypi
@@ -26,21 +26,20 @@
'uv_library%': 'static_library',
'clang%': 0,
+ 'error_on_warn%': 'false',
- 'openssl_fips%': '',
+ 'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)',
+ 'openssl_no_asm%': 0,
# Don't use ICU data file (icudtl.dat) from V8, we use our own.
'icu_use_data_file_flag%': 0,
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.44',
+ 'v8_embedder_string': '-node.26',
##### V8 defaults for Node.js #####
- # Old time default, now explicitly stated.
- 'v8_use_snapshot': 1,
-
# Turn on SipHash for hash seed generation, addresses HashWick
'v8_use_siphash': 'true',
@@ -61,9 +60,14 @@
# https://github.com/nodejs/node/pull/22920/files#r222779926
'v8_enable_handle_zapping': 0,
- # Disable V8 untrusted code mitigations.
- # See https://github.com/v8/v8/wiki/Untrusted-code-mitigations
- 'v8_untrusted_code_mitigations': 0,
+ # Disable pointer compression. Can be enabled at build time via configure
+ # options but default values are required here as this file is also used by
+ # node-gyp to build addons.
+ 'v8_enable_pointer_compression%': 0,
+ 'v8_enable_31bit_smis_on_64bit_arch%': 0,
+
+ # Disable v8 hugepage by default.
+ 'v8_enable_hugepage%': 0,
# This is more of a V8 dev setting
# https://github.com/nodejs/node/pull/22920/files#r222779926
@@ -77,67 +81,42 @@
##### end V8 defaults #####
'conditions': [
- ['target_arch=="arm64"', {
- # Disabled pending https://github.com/nodejs/node/issues/23913.
- 'openssl_no_asm%': 1,
- }, {
- 'openssl_no_asm%': 0,
- }],
['OS == "win"', {
'os_posix': 0,
'v8_postmortem_support%': 0,
+ 'obj_dir': '<(PRODUCT_DIR)/obj',
+ 'v8_base': '<(PRODUCT_DIR)/lib/libv8_snapshot.a',
}, {
'os_posix': 1,
'v8_postmortem_support%': 1,
}],
- ['v8_use_snapshot==1', {
- 'conditions': [
- ['GENERATOR == "ninja"', {
- 'obj_dir': '<(PRODUCT_DIR)/obj',
- 'v8_base': '<(PRODUCT_DIR)/obj/tools/v8_gypfiles/libv8_snapshot.a',
- }, {
- 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
- 'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_snapshot.a',
- }],
- ['OS == "win"', {
- 'obj_dir': '<(PRODUCT_DIR)/obj',
- 'v8_base': '<(PRODUCT_DIR)/lib/libv8_snapshot.a',
- }],
- ['OS == "mac" or OS == "ios"', {
- 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
- 'v8_base': '<(PRODUCT_DIR)/libv8_snapshot.a',
- }],
- ],
- }, {
- 'conditions': [
- ['GENERATOR == "ninja"', {
- 'obj_dir': '<(PRODUCT_DIR)/obj',
- 'v8_base': '<(PRODUCT_DIR)/obj/tools/v8_gypfiles/libv8_nosnapshot.a',
- }, {
- 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
- 'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_nosnapshot.a',
- }],
- ['OS == "win"', {
- 'obj_dir': '<(PRODUCT_DIR)/obj',
- 'v8_base': '<(PRODUCT_DIR)/lib/libv8_nosnapshot.a',
- }],
- ['OS == "mac" or OS == "ios"', {
- 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
- 'v8_base': '<(PRODUCT_DIR)/libv8_nosnapshot.a',
- }],
- ],
- }],
- ['openssl_fips != ""', {
- 'openssl_product': '<(STATIC_LIB_PREFIX)crypto<(STATIC_LIB_SUFFIX)',
+ ['GENERATOR == "ninja"', {
+ 'obj_dir': '<(PRODUCT_DIR)/obj',
+ 'v8_base': '<(PRODUCT_DIR)/obj/tools/v8_gypfiles/libv8_snapshot.a',
}, {
- 'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)',
+ 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
+ 'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_snapshot.a',
}],
['OS=="mac" or OS == "ios"', {
'clang%': 1,
+ 'obj_dir%': '<(PRODUCT_DIR)/obj.target',
+ 'v8_base': '<(PRODUCT_DIR)/libv8_snapshot.a',
+ }],
+ # V8 pointer compression only supports 64bit architectures.
+ ['target_arch in "arm ia32 mips mipsel ppc"', {
+ 'v8_enable_pointer_compression': 0,
+ 'v8_enable_31bit_smis_on_64bit_arch': 0,
}],
['target_arch in "ppc64 s390x"', {
'v8_enable_backtrace': 1,
}],
+ ['OS=="linux"', {
+ 'node_section_ordering_info%': ''
+ }],
+ ['OS == "zos"', {
+ # use ICU data file on z/OS
+ 'icu_use_data_file_flag%': 1
+ }]
],
},
@@ -158,7 +137,7 @@
'defines': [ 'DEBUG', '_DEBUG', 'V8_ENABLE_CHECKS' ],
'cflags': [ '-g', '-O0' ],
'conditions': [
- ['OS=="aix"', {
+ ['OS in "aix os400"', {
'cflags': [ '-gxcoff' ],
'ldflags': [ '-Wl,-bbigtoc' ],
}],
@@ -188,22 +167,54 @@
'v8_enable_handle_zapping': 0,
'pgo_generate': ' -fprofile-generate ',
'pgo_use': ' -fprofile-use -fprofile-correction ',
- 'lto': ' -flto=4 -fuse-linker-plugin -ffat-lto-objects ',
'conditions': [
['node_shared != "true"', {
'MSVC_runtimeType': 0 # MultiThreaded (/MT)
}, {
'MSVC_runtimeType': 2 # MultiThreadedDLL (/MD)
}],
+ ['llvm_version=="0.0"', {
+ 'lto': ' -flto=4 -fuse-linker-plugin -ffat-lto-objects ', # GCC
+ }, {
+ 'lto': ' -flto ', # Clang
+ }],
],
},
'cflags': [ '-O3' ],
'conditions': [
+ ['enable_lto=="true"', {
+ 'cflags': ['<(lto)'],
+ 'ldflags': ['<(lto)'],
+ 'xcode_settings': {
+ 'LLVM_LTO': 'YES',
+ },
+ }],
+ ['OS=="linux"', {
+ 'conditions': [
+ ['node_section_ordering_info!=""', {
+ 'cflags': [
+ '-fuse-ld=gold',
+ '-ffunction-sections',
+ ],
+ 'ldflags': [
+ '-fuse-ld=gold',
+ '-Wl,--section-ordering-file=<(node_section_ordering_info)',
+ ],
+ }],
+ ],
+ }],
['OS=="solaris"', {
# pull in V8's postmortem metadata
'ldflags': [ '-Wl,-z,allextract' ]
}],
- ['OS!="mac" and OS!="ios" and OS!="win"', {
+ ['OS=="zos"', {
+ # increase performance, number from experimentation
+ 'cflags': [ '-qINLINE=::150:100000' ]
+ }],
+ ['OS!="mac" and OS!="ios" and OS!="win" and OS!="zos"', {
+ # -fno-omit-frame-pointer is necessary for the --perf_basic_prof
+ # flag to work correctly. perf(1) gets confused about JS stack
+ # frames otherwise, even with --call-graph dwarf.
'cflags': [ '-fno-omit-frame-pointer' ],
}],
['OS=="linux"', {
@@ -216,10 +227,6 @@
'cflags': ['<(pgo_use)'],
'ldflags': ['<(pgo_use)'],
},],
- ['enable_lto=="true"', {
- 'cflags': ['<(lto)'],
- 'ldflags': ['<(lto)'],
- },],
],
},],
['OS == "android"', {
@@ -229,6 +236,11 @@
],
'msvs_settings': {
'VCCLCompilerTool': {
+ 'conditions': [
+ ['target_arch=="arm64"', {
+ 'FloatingPointModel': 1 # /fp:strict
+ }]
+ ],
'EnableFunctionLevelLinking': 'true',
'EnableIntrinsicFunctions': 'true',
'FavorSizeOrSpeed': 1, # /Ot, favor speed over size
@@ -250,14 +262,26 @@
'defines': [
'V8_DEPRECATION_WARNINGS',
'V8_IMMINENT_DEPRECATION_WARNINGS',
+ '_GLIBCXX_USE_CXX11_ABI=1',
],
# Forcibly disable -Werror. We support a wide range of compilers, it's
# simply not feasible to squelch all warnings, never mind that the
# libraries in deps/ are not under our control.
- 'cflags!': ['-Werror'],
+ 'conditions': [
+ [ 'error_on_warn=="false"', {
+ 'cflags!': ['-Werror'],
+ }, '(_target_name!="<(node_lib_target_name)" or '
+ '_target_name!="<(node_core_target_name)")', {
+ 'cflags!': ['-Werror'],
+ }],
+ ],
'msvs_settings': {
'VCCLCompilerTool': {
+ 'AdditionalOptions': [
+ '/Zc:__cplusplus',
+ '-std:c++17'
+ ],
'BufferSecurityCheck': 'true',
'DebugInformationFormat': 1, # /Z7 embed info in .obj files
'ExceptionHandling': 0, # /EHsc
@@ -317,7 +341,7 @@
[ 'target_arch=="arm64"', {
'msvs_configuration_platform': 'arm64',
}],
- ['asan == 1 and OS != "mac" and OS !="ios"', {
+ ['asan == 1 and OS != "mac" and OS != "ios" and OS != "zos"', {
'cflags+': [
'-fno-omit-frame-pointer',
'-fsanitize=address',
@@ -345,6 +369,15 @@
}],
],
}],
+ ['v8_enable_pointer_compression == 1', {
+ 'defines': [
+ 'V8_COMPRESS_POINTERS',
+ 'V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE',
+ ],
+ }],
+ ['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', {
+ 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'],
+ }],
['OS == "win"', {
'defines': [
'WIN32',
@@ -360,13 +393,13 @@
'BUILDING_UV_SHARED=1',
],
}],
- [ 'OS in "linux freebsd openbsd solaris aix"', {
+ [ 'OS in "linux freebsd openbsd solaris aix os400"', {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],
- [ 'OS in "linux freebsd openbsd solaris android aix cloudabi"', {
+ [ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi"', {
'cflags': [ '-Wall', '-Wextra', '-Wno-unused-parameter', ],
- 'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++1y' ],
+ 'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++17' ],
'defines': [ '__STDC_FORMAT_MACROS' ],
'ldflags': [ '-rdynamic' ],
'target_conditions': [
@@ -384,23 +417,19 @@
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
- [ 'target_arch=="x32"', {
- 'cflags': [ '-mx32' ],
- 'ldflags': [ '-mx32' ],
- }],
[ 'target_arch=="x64"', {
'cflags': [ '-m64' ],
'ldflags': [ '-m64' ],
}],
- [ 'target_arch=="ppc" and OS!="aix"', {
+ [ 'target_arch=="ppc" and OS not in "aix os400"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
- [ 'target_arch=="ppc64" and OS!="aix"', {
+ [ 'target_arch=="ppc64" and OS not in "aix os400"', {
'cflags': [ '-m64', '-mminimal-toc' ],
'ldflags': [ '-m64' ],
}],
- [ 'target_arch=="s390x"', {
+ [ 'target_arch=="s390x" and OS=="linux"', {
'cflags': [ '-m64', '-march=z196' ],
'ldflags': [ '-m64', '-march=z196' ],
}],
@@ -415,7 +444,7 @@
}],
],
}],
- [ 'OS=="aix"', {
+ [ 'OS in "aix os400"', {
'variables': {
# Used to differentiate `AIX` and `OS400`(IBM i).
'aix_variant_name': '
+#include
+#include
+#include
+#include
+#include
+
+#include "cppgc/custom-space.h"
+#include "cppgc/internal/api-constants.h"
+#include "cppgc/internal/gc-info.h"
+#include "cppgc/type-traits.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+#if defined(__has_attribute)
+#if __has_attribute(assume_aligned)
+#define CPPGC_DEFAULT_ALIGNED \
+ __attribute__((assume_aligned(api_constants::kDefaultAlignment)))
+#define CPPGC_DOUBLE_WORD_ALIGNED \
+ __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
+#endif // __has_attribute(assume_aligned)
+#endif // defined(__has_attribute)
+
+#if !defined(CPPGC_DEFAULT_ALIGNED)
+#define CPPGC_DEFAULT_ALIGNED
+#endif
+
+#if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
+#define CPPGC_DOUBLE_WORD_ALIGNED
+#endif
+
+namespace cppgc {
+
+/**
+ * AllocationHandle is used to allocate garbage-collected objects.
+ */
+class AllocationHandle;
+
+namespace internal {
+
+// Similar to C++17 std::align_val_t;
+enum class AlignVal : size_t {};
+
+class V8_EXPORT MakeGarbageCollectedTraitInternal {
+ protected:
+ static inline void MarkObjectAsFullyConstructed(const void* payload) {
+ // See api_constants for an explanation of the constants.
+ std::atomic* atomic_mutable_bitfield =
+ reinterpret_cast*>(
+ const_cast(reinterpret_cast(
+ reinterpret_cast(payload) -
+ api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
+ // It's safe to split use load+store here (instead of a read-modify-write
+ // operation), since it's guaranteed that this 16-bit bitfield is only
+ // modified by a single thread. This is cheaper in terms of code bloat (on
+ // ARM) and performance.
+ uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed);
+ value |= api_constants::kFullyConstructedBitMask;
+ atomic_mutable_bitfield->store(value, std::memory_order_release);
+ }
+
+ // Dispatch based on compile-time information.
+ //
+ // Default implementation is for a custom space with >`kDefaultAlignment` byte
+ // alignment.
+ template
+ struct AllocationDispatcher final {
+ static void* Invoke(AllocationHandle& handle, size_t size) {
+ static_assert(std::is_base_of::value,
+ "Custom space must inherit from CustomSpaceBase.");
+ static_assert(
+ !CustomSpace::kSupportsCompaction,
+ "Custom spaces that support compaction do not support allocating "
+ "objects with non-default (i.e. word-sized) alignment.");
+ return MakeGarbageCollectedTraitInternal::Allocate(
+ handle, size, static_cast(alignment),
+ internal::GCInfoTrait::Index(), CustomSpace::kSpaceIndex);
+ }
+ };
+
+ // Fast path for regular allocations for the default space with
+ // `kDefaultAlignment` byte alignment.
+ template
+ struct AllocationDispatcher
+ final {
+ static void* Invoke(AllocationHandle& handle, size_t size) {
+ return MakeGarbageCollectedTraitInternal::Allocate(
+ handle, size, internal::GCInfoTrait::Index());
+ }
+ };
+
+ // Default space with >`kDefaultAlignment` byte alignment.
+ template
+ struct AllocationDispatcher final {
+ static void* Invoke(AllocationHandle& handle, size_t size) {
+ return MakeGarbageCollectedTraitInternal::Allocate(
+ handle, size, static_cast(alignment),
+ internal::GCInfoTrait::Index());
+ }
+ };
+
+ // Custom space with `kDefaultAlignment` byte alignment.
+ template
+ struct AllocationDispatcher
+ final {
+ static void* Invoke(AllocationHandle& handle, size_t size) {
+ static_assert(std::is_base_of::value,
+ "Custom space must inherit from CustomSpaceBase.");
+ return MakeGarbageCollectedTraitInternal::Allocate(
+ handle, size, internal::GCInfoTrait::Index(),
+ CustomSpace::kSpaceIndex);
+ }
+ };
+
+ private:
+ static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
+ GCInfoIndex);
+ static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
+ size_t, AlignVal,
+ GCInfoIndex);
+ static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
+ GCInfoIndex, CustomSpaceIndex);
+ static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
+ size_t, AlignVal, GCInfoIndex,
+ CustomSpaceIndex);
+
+ friend class HeapObjectHeader;
+};
+
+} // namespace internal
+
+/**
+ * Base trait that provides utilities for advancers users that have custom
+ * allocation needs (e.g., overriding size). It's expected that users override
+ * MakeGarbageCollectedTrait (see below) and inherit from
+ * MakeGarbageCollectedTraitBase and make use of the low-level primitives
+ * offered to allocate and construct an object.
+ */
+template
+class MakeGarbageCollectedTraitBase
+ : private internal::MakeGarbageCollectedTraitInternal {
+ private:
+ static_assert(internal::IsGarbageCollectedType::value,
+ "T needs to be a garbage collected object");
+ static_assert(!IsGarbageCollectedWithMixinTypeV ||
+ sizeof(T) <=
+ internal::api_constants::kLargeObjectSizeThreshold,
+ "GarbageCollectedMixin may not be a large object");
+
+ protected:
+ /**
+ * Allocates memory for an object of type T.
+ *
+ * \param handle AllocationHandle identifying the heap to allocate the object
+ * on.
+ * \param size The size that should be reserved for the object.
+ * \returns the memory to construct an object of type T on.
+ */
+ V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
+ static_assert(
+ std::is_base_of::value,
+ "U of GarbageCollected must be a base of T. Check "
+ "GarbageCollected base class inheritance.");
+ static constexpr size_t kWantedAlignment =
+ alignof(T) < internal::api_constants::kDefaultAlignment
+ ? internal::api_constants::kDefaultAlignment
+ : alignof(T);
+ static_assert(
+ kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
+ "Requested alignment larger than alignof(std::max_align_t) bytes. "
+ "Please file a bug to possibly get this restriction lifted.");
+ return AllocationDispatcher<
+ typename internal::GCInfoFolding<
+ T, typename T::ParentMostGarbageCollectedType>::ResultType,
+ typename SpaceTrait::Space, kWantedAlignment>::Invoke(handle, size);
+ }
+
+ /**
+ * Marks an object as fully constructed, resulting in precise handling by the
+ * garbage collector.
+ *
+ * \param payload The base pointer the object is allocated at.
+ */
+ V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
+ internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
+ payload);
+ }
+};
+
+/**
+ * Passed to MakeGarbageCollected to specify how many bytes should be appended
+ * to the allocated object.
+ *
+ * Example:
+ * \code
+ * class InlinedArray final : public GarbageCollected {
+ * public:
+ * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
+ * void Trace(Visitor*) const {}
+
+ * size_t size;
+ * char* byte_array;
+ * };
+ *
+ * auto* inlined_array = MakeGarbageCollectedbyte_array[i]);
+ * }
+ * \endcode
+ */
+struct AdditionalBytes {
+ constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
+ const size_t value;
+};
+
+/**
+ * Default trait class that specifies how to construct an object of type T.
+ * Advanced users may override how an object is constructed using the utilities
+ * that are provided through MakeGarbageCollectedTraitBase.
+ *
+ * Any trait overriding construction must
+ * - allocate through `MakeGarbageCollectedTraitBase::Allocate`;
+ * - mark the object as fully constructed using
+ * `MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed`;
+ */
+template
+class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase {
+ public:
+ template
+ static T* Call(AllocationHandle& handle, Args&&... args) {
+ void* memory =
+ MakeGarbageCollectedTraitBase::Allocate(handle, sizeof(T));
+ T* object = ::new (memory) T(std::forward(args)...);
+ MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object);
+ return object;
+ }
+
+ template
+ static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
+ Args&&... args) {
+ void* memory = MakeGarbageCollectedTraitBase::Allocate(
+ handle, sizeof(T) + additional_bytes.value);
+ T* object = ::new (memory) T(std::forward(args)...);
+ MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object);
+ return object;
+ }
+};
+
+/**
+ * Allows users to specify a post-construction callback for specific types. The
+ * callback is invoked on the instance of type T right after it has been
+ * constructed. This can be useful when the callback requires a
+ * fully-constructed object to be able to dispatch to virtual methods.
+ */
+template
+struct PostConstructionCallbackTrait {
+ static void Call(T*) {}
+};
+
+/**
+ * Constructs a managed object of type T where T transitively inherits from
+ * GarbageCollected.
+ *
+ * \param args List of arguments with which an instance of T will be
+ * constructed.
+ * \returns an instance of type T.
+ */
+template
+V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
+ T* object =
+ MakeGarbageCollectedTrait::Call(handle, std::forward(args)...);
+ PostConstructionCallbackTrait::Call(object);
+ return object;
+}
+
+/**
+ * Constructs a managed object of type T where T transitively inherits from
+ * GarbageCollected. Created objects will have additional bytes appended to
+ * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
+ *
+ * \param additional_bytes Denotes how many bytes to append to T.
+ * \param args List of arguments with which an instance of T will be
+ * constructed.
+ * \returns an instance of type T.
+ */
+template
+V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
+ AdditionalBytes additional_bytes,
+ Args&&... args) {
+ T* object = MakeGarbageCollectedTrait::Call(handle, additional_bytes,
+ std::forward(args)...);
+ PostConstructionCallbackTrait::Call(object);
+ return object;
+}
+
+} // namespace cppgc
+
+#undef CPPGC_DEFAULT_ALIGNED
+#undef CPPGC_DOUBLE_WORD_ALIGNED
+
+#endif // INCLUDE_CPPGC_ALLOCATION_H_
diff --git a/libs/android/libnode/include/node/cppgc/common.h b/libs/android/libnode/include/node/cppgc/common.h
new file mode 100644
index 0000000..b6dbff3
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/common.h
@@ -0,0 +1,29 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_COMMON_H_
+#define INCLUDE_CPPGC_COMMON_H_
+
+// TODO(chromium:1056170): Remove dependency on v8.
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+/**
+ * Indicator for the stack state of the embedder.
+ */
+enum class EmbedderStackState {
+ /**
+ * Stack may contain interesting heap pointers.
+ */
+ kMayContainHeapPointers,
+ /**
+ * Stack does not contain any interesting heap pointers.
+ */
+ kNoHeapPointers,
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_COMMON_H_
diff --git a/libs/android/libnode/include/node/cppgc/cross-thread-persistent.h b/libs/android/libnode/include/node/cppgc/cross-thread-persistent.h
new file mode 100644
index 0000000..c8751e1
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/cross-thread-persistent.h
@@ -0,0 +1,465 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
+#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
+
+#include
+
+#include "cppgc/internal/persistent-node.h"
+#include "cppgc/internal/pointer-policies.h"
+#include "cppgc/persistent.h"
+#include "cppgc/visitor.h"
+
+namespace cppgc {
+namespace internal {
+
+// Wrapper around PersistentBase that allows accessing poisoned memory when
+// using ASAN. This is needed as the GC of the heap that owns the value
+// of a CTP, may clear it (heap termination, weakness) while the object
+// holding the CTP may be poisoned as itself may be deemed dead.
+class CrossThreadPersistentBase : public PersistentBase {
+ public:
+ CrossThreadPersistentBase() = default;
+ explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {}
+
+ V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const {
+ return raw_;
+ }
+
+ V8_CLANG_NO_SANITIZE("address")
+ PersistentNode* GetNodeFromGC() const { return node_; }
+
+ V8_CLANG_NO_SANITIZE("address")
+ void ClearFromGC() const {
+ raw_ = nullptr;
+ SetNodeSafe(nullptr);
+ }
+
+ // GetNodeSafe() can be used for a thread-safe IsValid() check in a
+ // double-checked locking pattern. See ~BasicCrossThreadPersistent.
+ PersistentNode* GetNodeSafe() const {
+ return reinterpret_cast*>(&node_)->load(
+ std::memory_order_acquire);
+ }
+
+ // The GC writes using SetNodeSafe() while holding the lock.
+ V8_CLANG_NO_SANITIZE("address")
+ void SetNodeSafe(PersistentNode* value) const {
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define V8_IS_ASAN 1
+#endif
+#endif
+
+#ifdef V8_IS_ASAN
+ __atomic_store(&node_, &value, __ATOMIC_RELEASE);
+#else // !V8_IS_ASAN
+ // Non-ASAN builds can use atomics. This also covers MSVC which does not
+ // have the __atomic_store intrinsic.
+ reinterpret_cast*>(&node_)->store(
+ value, std::memory_order_release);
+#endif // !V8_IS_ASAN
+
+#undef V8_IS_ASAN
+ }
+};
+
+template
+class BasicCrossThreadPersistent final : public CrossThreadPersistentBase,
+ public LocationPolicy,
+ private WeaknessPolicy,
+ private CheckingPolicy {
+ public:
+ using typename WeaknessPolicy::IsStrongPersistent;
+ using PointeeType = T;
+
+ ~BasicCrossThreadPersistent() {
+ // This implements fast path for destroying empty/sentinel.
+ //
+ // Simplified version of `AssignUnsafe()` to allow calling without a
+ // complete type `T`. Uses double-checked locking with a simple thread-safe
+ // check for a valid handle based on a node.
+ if (GetNodeSafe()) {
+ PersistentRegionLock guard;
+ const void* old_value = GetValue();
+ // The fast path check (GetNodeSafe()) does not acquire the lock. Recheck
+ // validity while holding the lock to ensure the reference has not been
+ // cleared.
+ if (IsValid(old_value)) {
+ CrossThreadPersistentRegion& region =
+ this->GetPersistentRegion(old_value);
+ region.FreeNode(GetNode());
+ SetNode(nullptr);
+ } else {
+ CPPGC_DCHECK(!GetNode());
+ }
+ }
+ // No need to call SetValue() as the handle is not used anymore. This can
+ // leave behind stale sentinel values but will always destroy the underlying
+ // node.
+ }
+
+ BasicCrossThreadPersistent(
+ const SourceLocation& loc = SourceLocation::Current())
+ : LocationPolicy(loc) {}
+
+ BasicCrossThreadPersistent(
+ std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
+ : LocationPolicy(loc) {}
+
+ BasicCrossThreadPersistent(
+ SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
+ : CrossThreadPersistentBase(s), LocationPolicy(loc) {}
+
+ BasicCrossThreadPersistent(
+ T* raw, const SourceLocation& loc = SourceLocation::Current())
+ : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
+ if (!IsValid(raw)) return;
+ PersistentRegionLock guard;
+ CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
+ SetNode(region.AllocateNode(this, &Trace));
+ this->CheckPointer(raw);
+ }
+
+ class UnsafeCtorTag {
+ private:
+ UnsafeCtorTag() = default;
+ template
+ friend class BasicCrossThreadPersistent;
+ };
+
+ BasicCrossThreadPersistent(
+ UnsafeCtorTag, T* raw,
+ const SourceLocation& loc = SourceLocation::Current())
+ : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
+ if (!IsValid(raw)) return;
+ CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
+ SetNode(region.AllocateNode(this, &Trace));
+ this->CheckPointer(raw);
+ }
+
+ BasicCrossThreadPersistent(
+ T& raw, const SourceLocation& loc = SourceLocation::Current())
+ : BasicCrossThreadPersistent(&raw, loc) {}
+
+ template ::value>>
+ BasicCrossThreadPersistent(
+ internal::BasicMember
+ member,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicCrossThreadPersistent(member.Get(), loc) {}
+
+ BasicCrossThreadPersistent(
+ const BasicCrossThreadPersistent& other,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicCrossThreadPersistent(loc) {
+ // Invoke operator=.
+ *this = other;
+ }
+
+ // Heterogeneous ctor.
+ template ::value>>
+ BasicCrossThreadPersistent(
+ const BasicCrossThreadPersistent& other,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicCrossThreadPersistent(loc) {
+ *this = other;
+ }
+
+ BasicCrossThreadPersistent(
+ BasicCrossThreadPersistent&& other,
+ const SourceLocation& loc = SourceLocation::Current()) noexcept {
+ // Invoke operator=.
+ *this = std::move(other);
+ }
+
+ BasicCrossThreadPersistent& operator=(
+ const BasicCrossThreadPersistent& other) {
+ PersistentRegionLock guard;
+ AssignSafe(guard, other.Get());
+ return *this;
+ }
+
+ template ::value>>
+ BasicCrossThreadPersistent& operator=(
+ const BasicCrossThreadPersistent& other) {
+ PersistentRegionLock guard;
+ AssignSafe(guard, other.Get());
+ return *this;
+ }
+
+ BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
+ if (this == &other) return *this;
+ Clear();
+ PersistentRegionLock guard;
+ PersistentBase::operator=(std::move(other));
+ LocationPolicy::operator=(std::move(other));
+ if (!IsValid(GetValue())) return *this;
+ GetNode()->UpdateOwner(this);
+ other.SetValue(nullptr);
+ other.SetNode(nullptr);
+ this->CheckPointer(Get());
+ return *this;
+ }
+
+ /**
+ * Assigns a raw pointer.
+ *
+ * Note: **Not thread-safe.**
+ */
+ BasicCrossThreadPersistent& operator=(T* other) {
+ AssignUnsafe(other);
+ return *this;
+ }
+
+ // Assignment from member.
+ template ::value>>
+ BasicCrossThreadPersistent& operator=(
+ internal::BasicMember
+ member) {
+ return operator=(member.Get());
+ }
+
+ /**
+ * Assigns a nullptr.
+ *
+ * \returns the handle.
+ */
+ BasicCrossThreadPersistent& operator=(std::nullptr_t) {
+ Clear();
+ return *this;
+ }
+
+ /**
+ * Assigns the sentinel pointer.
+ *
+ * \returns the handle.
+ */
+ BasicCrossThreadPersistent& operator=(SentinelPointer s) {
+ PersistentRegionLock guard;
+ AssignSafe(guard, s);
+ return *this;
+ }
+
+ /**
+ * Returns a pointer to the stored object.
+ *
+ * Note: **Not thread-safe.**
+ *
+ * \returns a pointer to the stored object.
+ */
+ // CFI cast exemption to allow passing SentinelPointer through T* and support
+ // heterogeneous assignments between different Member and Persistent handles
+ // based on their actual types.
+ V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
+ return static_cast(const_cast(GetValue()));
+ }
+
+ /**
+ * Clears the stored object.
+ */
+ void Clear() {
+ PersistentRegionLock guard;
+ AssignSafe(guard, nullptr);
+ }
+
+ /**
+ * Returns a pointer to the stored object and releases it.
+ *
+ * Note: **Not thread-safe.**
+ *
+ * \returns a pointer to the stored object.
+ */
+ T* Release() {
+ T* result = Get();
+ Clear();
+ return result;
+ }
+
+ /**
+ * Conversio to boolean.
+ *
+ * Note: **Not thread-safe.**
+ *
+ * \returns true if an actual object has been stored and false otherwise.
+ */
+ explicit operator bool() const { return Get(); }
+
+ /**
+ * Conversion to object of type T.
+ *
+ * Note: **Not thread-safe.**
+ *
+ * \returns the object.
+ */
+ operator T*() const { return Get(); }
+
+ /**
+ * Dereferences the stored object.
+ *
+ * Note: **Not thread-safe.**
+ */
+ T* operator->() const { return Get(); }
+ T& operator*() const { return *Get(); }
+
+ template
+ BasicCrossThreadPersistent
+ To() const {
+ using OtherBasicCrossThreadPersistent =
+ BasicCrossThreadPersistent;
+ PersistentRegionLock guard;
+ return OtherBasicCrossThreadPersistent(
+ typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
+ static_cast(Get()));
+ }
+
+ template ::IsStrongPersistent::value>::type>
+ BasicCrossThreadPersistent
+ Lock() const {
+ return BasicCrossThreadPersistent<
+ U, internal::StrongCrossThreadPersistentPolicy>(*this);
+ }
+
+ private:
+ static bool IsValid(const void* ptr) {
+ return ptr && ptr != kSentinelPointer;
+ }
+
+ static void Trace(Visitor* v, const void* ptr) {
+ const auto* handle = static_cast(ptr);
+ v->TraceRoot(*handle, handle->Location());
+ }
+
+ void AssignUnsafe(T* ptr) {
+ const void* old_value = GetValue();
+ if (IsValid(old_value)) {
+ PersistentRegionLock guard;
+ old_value = GetValue();
+ // The fast path check (IsValid()) does not acquire the lock. Reload
+ // the value to ensure the reference has not been cleared.
+ if (IsValid(old_value)) {
+ CrossThreadPersistentRegion& region =
+ this->GetPersistentRegion(old_value);
+ if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
+ SetValue(ptr);
+ this->CheckPointer(ptr);
+ return;
+ }
+ region.FreeNode(GetNode());
+ SetNode(nullptr);
+ } else {
+ CPPGC_DCHECK(!GetNode());
+ }
+ }
+ SetValue(ptr);
+ if (!IsValid(ptr)) return;
+ PersistentRegionLock guard;
+ SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
+ this->CheckPointer(ptr);
+ }
+
+ void AssignSafe(PersistentRegionLock&, T* ptr) {
+ PersistentRegionLock::AssertLocked();
+ const void* old_value = GetValue();
+ if (IsValid(old_value)) {
+ CrossThreadPersistentRegion& region =
+ this->GetPersistentRegion(old_value);
+ if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
+ SetValue(ptr);
+ this->CheckPointer(ptr);
+ return;
+ }
+ region.FreeNode(GetNode());
+ SetNode(nullptr);
+ }
+ SetValue(ptr);
+ if (!IsValid(ptr)) return;
+ SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
+ this->CheckPointer(ptr);
+ }
+
+ void ClearFromGC() const {
+ if (IsValid(GetValueFromGC())) {
+ WeaknessPolicy::GetPersistentRegion(GetValueFromGC())
+ .FreeNode(GetNodeFromGC());
+ CrossThreadPersistentBase::ClearFromGC();
+ }
+ }
+
+ // See Get() for details.
+ V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
+ T* GetFromGC() const {
+ return static_cast(const_cast(GetValueFromGC()));
+ }
+
+ friend class cppgc::Visitor;
+};
+
+template
+struct IsWeak<
+ BasicCrossThreadPersistent>
+ : std::true_type {};
+
+} // namespace internal
+
+namespace subtle {
+
+/**
+ * **DO NOT USE: Has known caveats, see below.**
+ *
+ * CrossThreadPersistent allows retaining objects from threads other than the
+ * thread the owning heap is operating on.
+ *
+ * Known caveats:
+ * - Does not protect the heap owning an object from terminating.
+ * - Reaching transitively through the graph is unsupported as objects may be
+ * moved concurrently on the thread owning the object.
+ */
+template
+using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
+ T, internal::StrongCrossThreadPersistentPolicy>;
+
+/**
+ * **DO NOT USE: Has known caveats, see below.**
+ *
+ * CrossThreadPersistent allows weakly retaining objects from threads other than
+ * the thread the owning heap is operating on.
+ *
+ * Known caveats:
+ * - Does not protect the heap owning an object from terminating.
+ * - Reaching transitively through the graph is unsupported as objects may be
+ * moved concurrently on the thread owning the object.
+ */
+template
+using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
+ T, internal::WeakCrossThreadPersistentPolicy>;
+
+} // namespace subtle
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
diff --git a/libs/android/libnode/include/node/cppgc/custom-space.h b/libs/android/libnode/include/node/cppgc/custom-space.h
new file mode 100644
index 0000000..757c4fd
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/custom-space.h
@@ -0,0 +1,97 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_
+#define INCLUDE_CPPGC_CUSTOM_SPACE_H_
+
+#include
+
+namespace cppgc {
+
+/**
+ * Index identifying a custom space.
+ */
+struct CustomSpaceIndex {
+ constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT
+ size_t value;
+};
+
+/**
+ * Top-level base class for custom spaces. Users must inherit from CustomSpace
+ * below.
+ */
+class CustomSpaceBase {
+ public:
+ virtual ~CustomSpaceBase() = default;
+ virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0;
+ virtual bool IsCompactable() const = 0;
+};
+
+/**
+ * Base class custom spaces should directly inherit from. The class inheriting
+ * from `CustomSpace` must define `kSpaceIndex` as unique space index. These
+ * indices need for form a sequence starting at 0.
+ *
+ * Example:
+ * \code
+ * class CustomSpace1 : public CustomSpace {
+ * public:
+ * static constexpr CustomSpaceIndex kSpaceIndex = 0;
+ * };
+ * class CustomSpace2 : public CustomSpace {
+ * public:
+ * static constexpr CustomSpaceIndex kSpaceIndex = 1;
+ * };
+ * \endcode
+ */
+template
+class CustomSpace : public CustomSpaceBase {
+ public:
+ /**
+ * Compaction is only supported on spaces that manually manage slots
+ * recording.
+ */
+ static constexpr bool kSupportsCompaction = false;
+
+ CustomSpaceIndex GetCustomSpaceIndex() const final {
+ return ConcreteCustomSpace::kSpaceIndex;
+ }
+ bool IsCompactable() const final {
+ return ConcreteCustomSpace::kSupportsCompaction;
+ }
+};
+
+/**
+ * User-overridable trait that allows pinning types to custom spaces.
+ */
+template
+struct SpaceTrait {
+ using Space = void;
+};
+
+namespace internal {
+
+template
+struct IsAllocatedOnCompactableSpaceImpl {
+ static constexpr bool value = CustomSpace::kSupportsCompaction;
+};
+
+template <>
+struct IsAllocatedOnCompactableSpaceImpl {
+ // Non-custom spaces are by default not compactable.
+ static constexpr bool value = false;
+};
+
+template
+struct IsAllocatedOnCompactableSpace {
+ public:
+ static constexpr bool value =
+ IsAllocatedOnCompactableSpaceImpl::Space>::value;
+};
+
+} // namespace internal
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_
diff --git a/libs/android/libnode/include/node/cppgc/default-platform.h b/libs/android/libnode/include/node/cppgc/default-platform.h
new file mode 100644
index 0000000..a27871c
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/default-platform.h
@@ -0,0 +1,67 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
+#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
+
+#include
+
+#include "cppgc/platform.h"
+#include "libplatform/libplatform.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+/**
+ * Platform provided by cppgc. Uses V8's DefaultPlatform provided by
+ * libplatform internally. Exception: `GetForegroundTaskRunner()`, see below.
+ */
+class V8_EXPORT DefaultPlatform : public Platform {
+ public:
+ using IdleTaskSupport = v8::platform::IdleTaskSupport;
+ explicit DefaultPlatform(
+ int thread_pool_size = 0,
+ IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
+ std::unique_ptr tracing_controller = {})
+ : v8_platform_(v8::platform::NewDefaultPlatform(
+ thread_pool_size, idle_task_support,
+ v8::platform::InProcessStackDumping::kDisabled,
+ std::move(tracing_controller))) {}
+
+ cppgc::PageAllocator* GetPageAllocator() override {
+ return v8_platform_->GetPageAllocator();
+ }
+
+ double MonotonicallyIncreasingTime() override {
+ return v8_platform_->MonotonicallyIncreasingTime();
+ }
+
+ std::shared_ptr GetForegroundTaskRunner() override {
+ // V8's default platform creates a new task runner when passed the
+ // `v8::Isolate` pointer the first time. For non-default platforms this will
+ // require getting the appropriate task runner.
+ return v8_platform_->GetForegroundTaskRunner(kNoIsolate);
+ }
+
+ std::unique_ptr PostJob(
+ cppgc::TaskPriority priority,
+ std::unique_ptr job_task) override {
+ return v8_platform_->PostJob(priority, std::move(job_task));
+ }
+
+ TracingController* GetTracingController() override {
+ return v8_platform_->GetTracingController();
+ }
+
+ v8::Platform* GetV8Platform() const { return v8_platform_.get(); }
+
+ protected:
+ static constexpr v8::Isolate* kNoIsolate = nullptr;
+
+ std::unique_ptr v8_platform_;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
diff --git a/libs/android/libnode/include/node/cppgc/ephemeron-pair.h b/libs/android/libnode/include/node/cppgc/ephemeron-pair.h
new file mode 100644
index 0000000..e16cf1f
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/ephemeron-pair.h
@@ -0,0 +1,30 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_
+#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_
+
+#include "cppgc/liveness-broker.h"
+#include "cppgc/member.h"
+
+namespace cppgc {
+
+/**
+ * An ephemeron pair is used to conditionally retain an object.
+ * The `value` will be kept alive only if the `key` is alive.
+ */
+template
+struct EphemeronPair {
+ EphemeronPair(K* k, V* v) : key(k), value(v) {}
+ WeakMember key;
+ Member value;
+
+ void ClearValueIfKeyIsDead(const LivenessBroker& broker) {
+ if (!broker.IsHeapObjectAlive(key)) value = nullptr;
+ }
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_
diff --git a/libs/android/libnode/include/node/cppgc/explicit-management.h b/libs/android/libnode/include/node/cppgc/explicit-management.h
new file mode 100644
index 0000000..0290328
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/explicit-management.h
@@ -0,0 +1,100 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
+#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
+
+#include
+
+#include "cppgc/allocation.h"
+#include "cppgc/internal/logging.h"
+#include "cppgc/type-traits.h"
+
+namespace cppgc {
+
+class HeapHandle;
+
+namespace subtle {
+
+template
+void FreeUnreferencedObject(HeapHandle& heap_handle, T& object);
+template
+bool Resize(T& object, AdditionalBytes additional_bytes);
+
+} // namespace subtle
+
+namespace internal {
+
+class ExplicitManagementImpl final {
+ private:
+ V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*);
+ V8_EXPORT static bool Resize(void*, size_t);
+
+ template
+ friend void subtle::FreeUnreferencedObject(HeapHandle&, T&);
+ template
+ friend bool subtle::Resize(T&, AdditionalBytes);
+};
+} // namespace internal
+
+namespace subtle {
+
+/**
+ * Informs the garbage collector that `object` can be immediately reclaimed. The
+ * destructor may not be invoked immediately but only on next garbage
+ * collection.
+ *
+ * It is up to the embedder to guarantee that no other object holds a reference
+ * to `object` after calling `FreeUnreferencedObject()`. In case such a
+ * reference exists, it's use results in a use-after-free.
+ *
+ * To aid in using the API, `FreeUnreferencedObject()` may be called from
+ * destructors on objects that would be reclaimed in the same garbage collection
+ * cycle.
+ *
+ * \param heap_handle The corresponding heap.
+ * \param object Reference to an object that is of type `GarbageCollected` and
+ * should be immediately reclaimed.
+ */
+template
+void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) {
+ static_assert(IsGarbageCollectedTypeV,
+ "Object must be of type GarbageCollected.");
+ internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle,
+ &object);
+}
+
+/**
+ * Tries to resize `object` of type `T` with additional bytes on top of
+ * sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
+ * `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
+ *
+ * `Resize()` performs growing or shrinking as needed and may skip the operation
+ * for internal reasons, see return value.
+ *
+ * It is up to the embedder to guarantee that in case of shrinking a larger
+ * object down, the reclaimed area is not used anymore. Any subsequent use
+ * results in a use-after-free.
+ *
+ * The `object` must be live when calling `Resize()`.
+ *
+ * \param object Reference to an object that is of type `GarbageCollected` and
+ * should be resized.
+ * \param additional_bytes Bytes in addition to sizeof(T) that the object should
+ * provide.
+ * \returns true when the operation was successful and the result can be relied
+ * on, and false otherwise.
+ */
+template
+bool Resize(T& object, AdditionalBytes additional_bytes) {
+ static_assert(IsGarbageCollectedTypeV,
+ "Object must be of type GarbageCollected.");
+ return internal::ExplicitManagementImpl::Resize(
+ &object, sizeof(T) + additional_bytes.value);
+}
+
+} // namespace subtle
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
diff --git a/libs/android/libnode/include/node/cppgc/garbage-collected.h b/libs/android/libnode/include/node/cppgc/garbage-collected.h
new file mode 100644
index 0000000..6737c8b
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/garbage-collected.h
@@ -0,0 +1,106 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
+#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
+
+#include "cppgc/internal/api-constants.h"
+#include "cppgc/platform.h"
+#include "cppgc/trace-trait.h"
+#include "cppgc/type-traits.h"
+
+namespace cppgc {
+
+class Visitor;
+
+/**
+ * Base class for managed objects. Only descendent types of `GarbageCollected`
+ * can be constructed using `MakeGarbageCollected()`. Must be inherited from as
+ * left-most base class.
+ *
+ * Types inheriting from GarbageCollected must provide a method of
+ * signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
+ * pointers to the visitor and delegates to garbage-collected base classes.
+ * The method must be virtual if the type is not directly a child of
+ * GarbageCollected and marked as final.
+ *
+ * \code
+ * // Example using final class.
+ * class FinalType final : public GarbageCollected {
+ * public:
+ * void Trace(cppgc::Visitor* visitor) const {
+ * // Dispatch using visitor->Trace(...);
+ * }
+ * };
+ *
+ * // Example using non-final base class.
+ * class NonFinalBase : public GarbageCollected {
+ * public:
+ * virtual void Trace(cppgc::Visitor*) const {}
+ * };
+ *
+ * class FinalChild final : public NonFinalBase {
+ * public:
+ * void Trace(cppgc::Visitor* visitor) const final {
+ * // Dispatch using visitor->Trace(...);
+ * NonFinalBase::Trace(visitor);
+ * }
+ * };
+ * \endcode
+ */
+template
+class GarbageCollected {
+ public:
+ using IsGarbageCollectedTypeMarker = void;
+ using ParentMostGarbageCollectedType = T;
+
+ // Must use MakeGarbageCollected.
+ void* operator new(size_t) = delete;
+ void* operator new[](size_t) = delete;
+ // The garbage collector is taking care of reclaiming the object. Also,
+ // virtual destructor requires an unambiguous, accessible 'operator delete'.
+ void operator delete(void*) {
+#ifdef V8_ENABLE_CHECKS
+ internal::Fatal(
+ "Manually deleting a garbage collected object is not allowed");
+#endif // V8_ENABLE_CHECKS
+ }
+ void operator delete[](void*) = delete;
+
+ protected:
+ GarbageCollected() = default;
+};
+
+/**
+ * Base class for managed mixin objects. Such objects cannot be constructed
+ * directly but must be mixed into the inheritance hierarchy of a
+ * GarbageCollected object.
+ *
+ * Types inheriting from GarbageCollectedMixin must override a virtual method
+ * of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
+ * pointers to the visitor and delegates to base classes.
+ *
+ * \code
+ * class Mixin : public GarbageCollectedMixin {
+ * public:
+ * void Trace(cppgc::Visitor* visitor) const override {
+ * // Dispatch using visitor->Trace(...);
+ * }
+ * };
+ * \endcode
+ */
+class GarbageCollectedMixin {
+ public:
+ using IsGarbageCollectedMixinTypeMarker = void;
+
+ /**
+ * This Trace method must be overriden by objects inheriting from
+ * GarbageCollectedMixin.
+ */
+ virtual void Trace(cppgc::Visitor*) const {}
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
diff --git a/libs/android/libnode/include/node/cppgc/heap-consistency.h b/libs/android/libnode/include/node/cppgc/heap-consistency.h
new file mode 100644
index 0000000..54a4dbc
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/heap-consistency.h
@@ -0,0 +1,266 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
+#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
+
+#include
+
+#include "cppgc/internal/write-barrier.h"
+#include "cppgc/macros.h"
+#include "cppgc/trace-trait.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+class HeapHandle;
+
+namespace subtle {
+
+/**
+ * **DO NOT USE: Use the appropriate managed types.**
+ *
+ * Consistency helpers that aid in maintaining a consistent internal state of
+ * the garbage collector.
+ */
+class HeapConsistency final {
+ public:
+ using WriteBarrierParams = internal::WriteBarrier::Params;
+ using WriteBarrierType = internal::WriteBarrier::Type;
+
+ /**
+ * Gets the required write barrier type for a specific write.
+ *
+ * \param slot Slot containing the pointer to the object. The slot itself
+ * must reside in an object that has been allocated using
+ * `MakeGarbageCollected()`.
+ * \param value The pointer to the object. May be an interior pointer to an
+ * interface of the actual object.
+ * \param params Parameters that may be used for actual write barrier calls.
+ * Only filled if return value indicates that a write barrier is needed. The
+ * contents of the `params` are an implementation detail.
+ * \returns whether a write barrier is needed and which barrier to invoke.
+ */
+ static V8_INLINE WriteBarrierType GetWriteBarrierType(
+ const void* slot, const void* value, WriteBarrierParams& params) {
+ return internal::WriteBarrier::GetWriteBarrierType(slot, value, params);
+ }
+
+ /**
+ * Gets the required write barrier type for a specific write.
+ *
+ * \param slot Slot to some part of an object. The object must not necessarily
+ have been allocated using `MakeGarbageCollected()` but can also live
+ off-heap or on stack.
+ * \param params Parameters that may be used for actual write barrier calls.
+ * Only filled if return value indicates that a write barrier is needed. The
+ * contents of the `params` are an implementation detail.
+ * \param callback Callback returning the corresponding heap handle. The
+ * callback is only invoked if the heap cannot otherwise be figured out. The
+ * callback must not allocate.
+ * \returns whether a write barrier is needed and which barrier to invoke.
+ */
+ template
+ static V8_INLINE WriteBarrierType
+ GetWriteBarrierType(const void* slot, WriteBarrierParams& params,
+ HeapHandleCallback callback) {
+ return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback);
+ }
+
+ /**
+ * Gets the required write barrier type for a specific write.
+ * This version is meant to be used in conjunction with with a marking write
+ * barrier barrier which doesn't consider the slot.
+ *
+ * \param value The pointer to the object. May be an interior pointer to an
+ * interface of the actual object.
+ * \param params Parameters that may be used for actual write barrier calls.
+ * Only filled if return value indicates that a write barrier is needed. The
+ * contents of the `params` are an implementation detail.
+ * \returns whether a write barrier is needed and which barrier to invoke.
+ */
+ static V8_INLINE WriteBarrierType
+ GetWriteBarrierType(const void* value, WriteBarrierParams& params) {
+ return internal::WriteBarrier::GetWriteBarrierType(value, params);
+ }
+
+ /**
+ * Conservative Dijkstra-style write barrier that processes an object if it
+ * has not yet been processed.
+ *
+ * \param params The parameters retrieved from `GetWriteBarrierType()`.
+ * \param object The pointer to the object. May be an interior pointer to a
+ * an interface of the actual object.
+ */
+ static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params,
+ const void* object) {
+ internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
+ }
+
+ /**
+ * Conservative Dijkstra-style write barrier that processes a range of
+ * elements if they have not yet been processed.
+ *
+ * \param params The parameters retrieved from `GetWriteBarrierType()`.
+ * \param first_element Pointer to the first element that should be processed.
+ * The slot itself must reside in an object that has been allocated using
+ * `MakeGarbageCollected()`.
+ * \param element_size Size of the element in bytes.
+ * \param number_of_elements Number of elements that should be processed,
+ * starting with `first_element`.
+ * \param trace_callback The trace callback that should be invoked for each
+ * element if necessary.
+ */
+ static V8_INLINE void DijkstraWriteBarrierRange(
+ const WriteBarrierParams& params, const void* first_element,
+ size_t element_size, size_t number_of_elements,
+ TraceCallback trace_callback) {
+ internal::WriteBarrier::DijkstraMarkingBarrierRange(
+ params, first_element, element_size, number_of_elements,
+ trace_callback);
+ }
+
+ /**
+ * Steele-style write barrier that re-processes an object if it has already
+ * been processed.
+ *
+ * \param params The parameters retrieved from `GetWriteBarrierType()`.
+ * \param object The pointer to the object which must point to an object that
+ * has been allocated using `MakeGarbageCollected()`. Interior pointers are
+ * not supported.
+ */
+ static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params,
+ const void* object) {
+ internal::WriteBarrier::SteeleMarkingBarrier(params, object);
+ }
+
+ /**
+ * Generational barrier for maintaining consistency when running with multiple
+ * generations.
+ *
+ * \param params The parameters retrieved from `GetWriteBarrierType()`.
+ * \param slot Slot containing the pointer to the object. The slot itself
+ * must reside in an object that has been allocated using
+ * `MakeGarbageCollected()`.
+ */
+ static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
+ const void* slot) {
+ internal::WriteBarrier::GenerationalBarrier(params, slot);
+ }
+
+ /**
+ * Generational barrier for source object that may contain outgoing pointers
+ * to objects in young generation.
+ *
+ * \param params The parameters retrieved from `GetWriteBarrierType()`.
+ * \param inner_pointer Pointer to the source object.
+ */
+ static V8_INLINE void GenerationalBarrierForSourceObject(
+ const WriteBarrierParams& params, const void* inner_pointer) {
+ internal::WriteBarrier::GenerationalBarrierForSourceObject(params,
+ inner_pointer);
+ }
+
+ private:
+ HeapConsistency() = delete;
+};
+
+/**
+ * Disallows garbage collection finalizations. Any garbage collection triggers
+ * result in a crash when in this scope.
+ *
+ * Note that the garbage collector already covers paths that can lead to garbage
+ * collections, so user code does not require checking
+ * `IsGarbageCollectionAllowed()` before allocations.
+ */
+class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final {
+ CPPGC_STACK_ALLOCATED();
+
+ public:
+ /**
+ * \returns whether garbage collections are currently allowed.
+ */
+ static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle);
+
+ /**
+ * Enters a disallow garbage collection scope. Must be paired with `Leave()`.
+ * Prefer a scope instance of `DisallowGarbageCollectionScope`.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ static void Enter(HeapHandle& heap_handle);
+
+ /**
+ * Leaves a disallow garbage collection scope. Must be paired with `Enter()`.
+ * Prefer a scope instance of `DisallowGarbageCollectionScope`.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ static void Leave(HeapHandle& heap_handle);
+
+ /**
+ * Constructs a scoped object that automatically enters and leaves a disallow
+ * garbage collection scope based on its lifetime.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle);
+ ~DisallowGarbageCollectionScope();
+
+ DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) =
+ delete;
+ DisallowGarbageCollectionScope& operator=(
+ const DisallowGarbageCollectionScope&) = delete;
+
+ private:
+ HeapHandle& heap_handle_;
+};
+
+/**
+ * Avoids invoking garbage collection finalizations. Already running garbage
+ * collection phase are unaffected by this scope.
+ *
+ * Should only be used temporarily as the scope has an impact on memory usage
+ * and follow up garbage collections.
+ */
+class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final {
+ CPPGC_STACK_ALLOCATED();
+
+ public:
+ /**
+ * Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer
+ * a scope instance of `NoGarbageCollectionScope`.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ static void Enter(HeapHandle& heap_handle);
+
+ /**
+ * Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer
+ * a scope instance of `NoGarbageCollectionScope`.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ static void Leave(HeapHandle& heap_handle);
+
+ /**
+ * Constructs a scoped object that automatically enters and leaves a no
+ * garbage collection scope based on its lifetime.
+ *
+ * \param heap_handle The corresponding heap.
+ */
+ explicit NoGarbageCollectionScope(HeapHandle& heap_handle);
+ ~NoGarbageCollectionScope();
+
+ NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete;
+ NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete;
+
+ private:
+ HeapHandle& heap_handle_;
+};
+
+} // namespace subtle
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
diff --git a/libs/android/libnode/include/node/cppgc/heap-state.h b/libs/android/libnode/include/node/cppgc/heap-state.h
new file mode 100644
index 0000000..2821258
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/heap-state.h
@@ -0,0 +1,82 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_HEAP_STATE_H_
+#define INCLUDE_CPPGC_HEAP_STATE_H_
+
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+class HeapHandle;
+
+namespace subtle {
+
+/**
+ * Helpers to peek into heap-internal state.
+ */
+class V8_EXPORT HeapState final {
+ public:
+ /**
+ * Returns whether the garbage collector is marking. This API is experimental
+ * and is expected to be removed in future.
+ *
+ * \param heap_handle The corresponding heap.
+ * \returns true if the garbage collector is currently marking, and false
+ * otherwise.
+ */
+ static bool IsMarking(const HeapHandle& heap_handle);
+
+ /*
+ * Returns whether the garbage collector is sweeping. This API is experimental
+ * and is expected to be removed in future.
+ *
+ * \param heap_handle The corresponding heap.
+ * \returns true if the garbage collector is currently sweeping, and false
+ * otherwise.
+ */
+ static bool IsSweeping(const HeapHandle& heap_handle);
+
+ /*
+ * Returns whether the garbage collector is currently sweeping on the thread
+ * owning this heap. This API allows the caller to determine whether it has
+ * been called from a destructor of a managed object. This API is experimental
+ * and may be removed in future.
+ *
+ * \param heap_handle The corresponding heap.
+ * \returns true if the garbage collector is currently sweeping on this
+ * thread, and false otherwise.
+ */
+ static bool IsSweepingOnOwningThread(const HeapHandle& heap_handle);
+
+ /**
+ * Returns whether the garbage collector is in the atomic pause, i.e., the
+ * mutator is stopped from running. This API is experimental and is expected
+ * to be removed in future.
+ *
+ * \param heap_handle The corresponding heap.
+ * \returns true if the garbage collector is currently in the atomic pause,
+ * and false otherwise.
+ */
+ static bool IsInAtomicPause(const HeapHandle& heap_handle);
+
+ /**
+ * Returns whether the last garbage collection was finalized conservatively
+ * (i.e., with a non-empty stack). This API is experimental and is expected to
+ * be removed in future.
+ *
+ * \param heap_handle The corresponding heap.
+ * \returns true if the last garbage collection was finalized conservatively,
+ * and false otherwise.
+ */
+ static bool PreviousGCWasConservative(const HeapHandle& heap_handle);
+
+ private:
+ HeapState() = delete;
+};
+
+} // namespace subtle
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_HEAP_STATE_H_
diff --git a/libs/android/libnode/include/node/cppgc/heap-statistics.h b/libs/android/libnode/include/node/cppgc/heap-statistics.h
new file mode 100644
index 0000000..8e62659
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/heap-statistics.h
@@ -0,0 +1,120 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_
+#define INCLUDE_CPPGC_HEAP_STATISTICS_H_
+
+#include
+#include
+#include
+#include
+
+namespace cppgc {
+
+/**
+ * `HeapStatistics` contains memory consumption and utilization statistics for a
+ * cppgc heap.
+ */
+struct HeapStatistics final {
+ /**
+ * Specifies the detail level of the heap statistics. Brief statistics contain
+ * only the top-level allocated and used memory statistics for the entire
+ * heap. Detailed statistics also contain a break down per space and page, as
+ * well as freelist statistics and object type histograms. Note that used
+ * memory reported by brief statistics and detailed statistics might differ
+ * slightly.
+ */
+ enum DetailLevel : uint8_t {
+ kBrief,
+ kDetailed,
+ };
+
+ /**
+ * Object statistics for a single type.
+ */
+ struct ObjectStatsEntry {
+ /**
+ * Number of allocated bytes.
+ */
+ size_t allocated_bytes;
+ /**
+ * Number of allocated objects.
+ */
+ size_t object_count;
+ };
+
+ /**
+ * Page granularity statistics. For each page the statistics record the
+ * allocated memory size and overall used memory size for the page.
+ */
+ struct PageStatistics {
+ /** Overall committed amount of memory for the page. */
+ size_t committed_size_bytes = 0;
+ /** Resident amount of memory held by the page. */
+ size_t resident_size_bytes = 0;
+ /** Amount of memory actually used on the page. */
+ size_t used_size_bytes = 0;
+ /** Statistics for object allocated on the page. Filled only when
+ * NameProvider::HideInternalNames() is false. */
+ std::vector object_statistics;
+ };
+
+ /**
+ * Statistics of the freelist (used only in non-large object spaces). For
+ * each bucket in the freelist the statistics record the bucket size, the
+ * number of freelist entries in the bucket, and the overall allocated memory
+ * consumed by these freelist entries.
+ */
+ struct FreeListStatistics {
+ /** bucket sizes in the freelist. */
+ std::vector bucket_size;
+ /** number of freelist entries per bucket. */
+ std::vector free_count;
+ /** memory size consumed by freelist entries per size. */
+ std::vector free_size;
+ };
+
+ /**
+ * Space granularity statistics. For each space the statistics record the
+ * space name, the amount of allocated memory and overall used memory for the
+ * space. The statistics also contain statistics for each of the space's
+ * pages, its freelist and the objects allocated on the space.
+ */
+ struct SpaceStatistics {
+ /** The space name */
+ std::string name;
+ /** Overall committed amount of memory for the heap. */
+ size_t committed_size_bytes = 0;
+ /** Resident amount of memory held by the heap. */
+ size_t resident_size_bytes = 0;
+ /** Amount of memory actually used on the space. */
+ size_t used_size_bytes = 0;
+ /** Statistics for each of the pages in the space. */
+ std::vector page_stats;
+ /** Statistics for the freelist of the space. */
+ FreeListStatistics free_list_stats;
+ };
+
+ /** Overall committed amount of memory for the heap. */
+ size_t committed_size_bytes = 0;
+ /** Resident amount of memory help by the heap. */
+ size_t resident_size_bytes = 0;
+ /** Amount of memory actually used on the heap. */
+ size_t used_size_bytes = 0;
+ /** Detail level of this HeapStatistics. */
+ DetailLevel detail_level;
+
+ /** Statistics for each of the spaces in the heap. Filled only when
+ * `detail_level` is `DetailLevel::kDetailed`. */
+ std::vector space_stats;
+
+ /**
+ * Vector of `cppgc::GarbageCollected` type names.
+ */
+ std::vector type_names;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_
diff --git a/libs/android/libnode/include/node/cppgc/heap.h b/libs/android/libnode/include/node/cppgc/heap.h
new file mode 100644
index 0000000..aa3c6f4
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/heap.h
@@ -0,0 +1,206 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_HEAP_H_
+#define INCLUDE_CPPGC_HEAP_H_
+
+#include
+#include
+#include
+#include
+
+#include "cppgc/common.h"
+#include "cppgc/custom-space.h"
+#include "cppgc/platform.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+/**
+ * cppgc - A C++ garbage collection library.
+ */
+namespace cppgc {
+
+class AllocationHandle;
+
+/**
+ * Implementation details of cppgc. Those details are considered internal and
+ * may change at any point in time without notice. Users should never rely on
+ * the contents of this namespace.
+ */
+namespace internal {
+class Heap;
+} // namespace internal
+
+/**
+ * Used for additional heap APIs.
+ */
+class HeapHandle;
+
+class V8_EXPORT Heap {
+ public:
+ /**
+ * Specifies the stack state the embedder is in.
+ */
+ using StackState = EmbedderStackState;
+
+ /**
+ * Specifies whether conservative stack scanning is supported.
+ */
+ enum class StackSupport : uint8_t {
+ /**
+ * Conservative stack scan is supported.
+ */
+ kSupportsConservativeStackScan,
+ /**
+ * Conservative stack scan is not supported. Embedders may use this option
+ * when using custom infrastructure that is unsupported by the library.
+ */
+ kNoConservativeStackScan,
+ };
+
+ /**
+ * Specifies supported marking types
+ */
+ enum class MarkingType : uint8_t {
+ /**
+ * Atomic stop-the-world marking. This option does not require any write
+ * barriers but is the most intrusive in terms of jank.
+ */
+ kAtomic,
+ /**
+ * Incremental marking interleaves marking with the rest of the application
+ * workload on the same thread.
+ */
+ kIncremental,
+ /**
+ * Incremental and concurrent marking.
+ */
+ kIncrementalAndConcurrent
+ };
+
+ /**
+ * Specifies supported sweeping types
+ */
+ enum class SweepingType : uint8_t {
+ /**
+ * Atomic stop-the-world sweeping. All of sweeping is performed at once.
+ */
+ kAtomic,
+ /**
+ * Incremental sweeping interleaves sweeping with the rest of the
+ * application workload on the same thread.
+ */
+ kIncremental,
+ /**
+ * Incremental and concurrent sweeping. Sweeping is split and interleaved
+ * with the rest of the application.
+ */
+ kIncrementalAndConcurrent
+ };
+
+ /**
+ * Constraints for a Heap setup.
+ */
+ struct ResourceConstraints {
+ /**
+ * Allows the heap to grow to some initial size in bytes before triggering
+ * garbage collections. This is useful when it is known that applications
+ * need a certain minimum heap to run to avoid repeatedly invoking the
+ * garbage collector when growing the heap.
+ */
+ size_t initial_heap_size_bytes = 0;
+ };
+
+ /**
+ * Options specifying Heap properties (e.g. custom spaces) when initializing a
+ * heap through `Heap::Create()`.
+ */
+ struct HeapOptions {
+ /**
+ * Creates reasonable defaults for instantiating a Heap.
+ *
+ * \returns the HeapOptions that can be passed to `Heap::Create()`.
+ */
+ static HeapOptions Default() { return {}; }
+
+ /**
+ * Custom spaces added to heap are required to have indices forming a
+ * numbered sequence starting at 0, i.e., their `kSpaceIndex` must
+ * correspond to the index they reside in the vector.
+ */
+ std::vector> custom_spaces;
+
+ /**
+ * Specifies whether conservative stack scan is supported. When conservative
+ * stack scan is not supported, the collector may try to invoke
+ * garbage collections using non-nestable task, which are guaranteed to have
+ * no interesting stack, through the provided Platform. If such tasks are
+ * not supported by the Platform, the embedder must take care of invoking
+ * the GC through `ForceGarbageCollectionSlow()`.
+ */
+ StackSupport stack_support = StackSupport::kSupportsConservativeStackScan;
+
+ /**
+ * Specifies which types of marking are supported by the heap.
+ */
+ MarkingType marking_support = MarkingType::kIncrementalAndConcurrent;
+
+ /**
+ * Specifies which types of sweeping are supported by the heap.
+ */
+ SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent;
+
+ /**
+ * Resource constraints specifying various properties that the internal
+ * GC scheduler follows.
+ */
+ ResourceConstraints resource_constraints;
+ };
+
+ /**
+ * Creates a new heap that can be used for object allocation.
+ *
+ * \param platform implemented and provided by the embedder.
+ * \param options HeapOptions specifying various properties for the Heap.
+ * \returns a new Heap instance.
+ */
+ static std::unique_ptr Create(
+ std::shared_ptr platform,
+ HeapOptions options = HeapOptions::Default());
+
+ virtual ~Heap() = default;
+
+ /**
+ * Forces garbage collection.
+ *
+ * \param source String specifying the source (or caller) triggering a
+ * forced garbage collection.
+ * \param reason String specifying the reason for the forced garbage
+ * collection.
+ * \param stack_state The embedder stack state, see StackState.
+ */
+ void ForceGarbageCollectionSlow(
+ const char* source, const char* reason,
+ StackState stack_state = StackState::kMayContainHeapPointers);
+
+ /**
+ * \returns the opaque handle for allocating objects using
+ * `MakeGarbageCollected()`.
+ */
+ AllocationHandle& GetAllocationHandle();
+
+ /**
+ * \returns the opaque heap handle which may be used to refer to this heap in
+ * other APIs. Valid as long as the underlying `Heap` is alive.
+ */
+ HeapHandle& GetHeapHandle();
+
+ private:
+ Heap() = default;
+
+ friend class internal::Heap;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_HEAP_H_
diff --git a/libs/android/libnode/include/node/cppgc/liveness-broker.h b/libs/android/libnode/include/node/cppgc/liveness-broker.h
new file mode 100644
index 0000000..c94eef0
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/liveness-broker.h
@@ -0,0 +1,77 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_
+#define INCLUDE_CPPGC_LIVENESS_BROKER_H_
+
+#include "cppgc/heap.h"
+#include "cppgc/member.h"
+#include "cppgc/trace-trait.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+namespace internal {
+class LivenessBrokerFactory;
+} // namespace internal
+
+/**
+ * The broker is passed to weak callbacks to allow (temporarily) querying
+ * the liveness state of an object. References to non-live objects must be
+ * cleared when `IsHeapObjectAlive()` returns false.
+ *
+ * \code
+ * class GCedWithCustomWeakCallback final
+ * : public GarbageCollected {
+ * public:
+ * UntracedMember bar;
+ *
+ * void CustomWeakCallbackMethod(const LivenessBroker& broker) {
+ * if (!broker.IsHeapObjectAlive(bar))
+ * bar = nullptr;
+ * }
+ *
+ * void Trace(cppgc::Visitor* visitor) const {
+ * visitor->RegisterWeakCallbackMethod<
+ * GCedWithCustomWeakCallback,
+ * &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this);
+ * }
+ * };
+ * \endcode
+ */
+class V8_EXPORT LivenessBroker final {
+ public:
+ template
+ bool IsHeapObjectAlive(const T* object) const {
+ // nullptr objects are considered alive to allow weakness to be used from
+ // stack while running into a conservative GC. Treating nullptr as dead
+ // would mean that e.g. custom collectins could not be strongified on stack.
+ return !object ||
+ IsHeapObjectAliveImpl(
+ TraceTrait::GetTraceDescriptor(object).base_object_payload);
+ }
+
+ template
+ bool IsHeapObjectAlive(const WeakMember& weak_member) const {
+ return (weak_member != kSentinelPointer) &&
+ IsHeapObjectAlive(weak_member.Get());
+ }
+
+ template
+ bool IsHeapObjectAlive(const UntracedMember& untraced_member) const {
+ return (untraced_member != kSentinelPointer) &&
+ IsHeapObjectAlive(untraced_member.Get());
+ }
+
+ private:
+ LivenessBroker() = default;
+
+ bool IsHeapObjectAliveImpl(const void*) const;
+
+ friend class internal::LivenessBrokerFactory;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_
diff --git a/libs/android/libnode/include/node/cppgc/macros.h b/libs/android/libnode/include/node/cppgc/macros.h
new file mode 100644
index 0000000..030f397
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/macros.h
@@ -0,0 +1,26 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_MACROS_H_
+#define INCLUDE_CPPGC_MACROS_H_
+
+#include
+
+#include "cppgc/internal/compiler-specific.h"
+
+namespace cppgc {
+
+// Use if the object is only stack allocated.
+#define CPPGC_STACK_ALLOCATED() \
+ public: \
+ using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \
+ \
+ private: \
+ void* operator new(size_t) = delete; \
+ void* operator new(size_t, void*) = delete; \
+ static_assert(true, "Force semicolon.")
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_MACROS_H_
diff --git a/libs/android/libnode/include/node/cppgc/member.h b/libs/android/libnode/include/node/cppgc/member.h
new file mode 100644
index 0000000..66a8cfd
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/member.h
@@ -0,0 +1,291 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_MEMBER_H_
+#define INCLUDE_CPPGC_MEMBER_H_
+
+#include
+#include
+#include
+
+#include "cppgc/internal/pointer-policies.h"
+#include "cppgc/sentinel-pointer.h"
+#include "cppgc/type-traits.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+class Visitor;
+
+namespace internal {
+
+// MemberBase always refers to the object as const object and defers to
+// BasicMember on casting to the right type as needed.
+class MemberBase {
+ protected:
+ struct AtomicInitializerTag {};
+
+ MemberBase() : raw_(nullptr) {}
+ explicit MemberBase(const void* value) : raw_(value) {}
+ MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); }
+
+ const void** GetRawSlot() const { return &raw_; }
+ const void* GetRaw() const { return raw_; }
+ void SetRaw(void* value) { raw_ = value; }
+
+ const void* GetRawAtomic() const {
+ return reinterpret_cast*>(&raw_)->load(
+ std::memory_order_relaxed);
+ }
+ void SetRawAtomic(const void* value) {
+ reinterpret_cast*>(&raw_)->store(
+ value, std::memory_order_relaxed);
+ }
+
+ void ClearFromGC() const { raw_ = nullptr; }
+
+ private:
+ // All constructors initialize `raw_`. Do not add a default value here as it
+ // results in a non-atomic write on some builds, even when the atomic version
+ // of the constructor is used.
+ mutable const void* raw_;
+};
+
+// The basic class from which all Member classes are 'generated'.
+template
+class BasicMember final : private MemberBase, private CheckingPolicy {
+ public:
+ using PointeeType = T;
+
+ constexpr BasicMember() = default;
+ constexpr BasicMember(std::nullptr_t) {} // NOLINT
+ BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT
+ BasicMember(T* raw) : MemberBase(raw) { // NOLINT
+ InitializingWriteBarrier();
+ this->CheckPointer(Get());
+ }
+ BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT
+ // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to
+ // initialize using atomic assignments. This is required for preventing
+ // data races with concurrent marking.
+ using AtomicInitializerTag = MemberBase::AtomicInitializerTag;
+ BasicMember(std::nullptr_t, AtomicInitializerTag atomic)
+ : MemberBase(nullptr, atomic) {}
+ BasicMember(SentinelPointer s, AtomicInitializerTag atomic)
+ : MemberBase(s, atomic) {}
+ BasicMember(T* raw, AtomicInitializerTag atomic) : MemberBase(raw, atomic) {
+ InitializingWriteBarrier();
+ this->CheckPointer(Get());
+ }
+ BasicMember(T& raw, AtomicInitializerTag atomic)
+ : BasicMember(&raw, atomic) {}
+ // Copy ctor.
+ BasicMember(const BasicMember& other) : BasicMember(other.Get()) {}
+ // Allow heterogeneous construction.
+ template ::value>>
+ BasicMember( // NOLINT
+ const BasicMember& other)
+ : BasicMember(other.Get()) {}
+ // Move ctor.
+ BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) {
+ other.Clear();
+ }
+ // Allow heterogeneous move construction.
+ template ::value>>
+ BasicMember(BasicMember&& other) noexcept
+ : BasicMember(other.Get()) {
+ other.Clear();
+ }
+ // Construction from Persistent.
+ template ::value>>
+ BasicMember(const BasicPersistent& p)
+ : BasicMember(p.Get()) {}
+
+ // Copy assignment.
+ BasicMember& operator=(const BasicMember& other) {
+ return operator=(other.Get());
+ }
+ // Allow heterogeneous copy assignment.
+ template ::value>>
+ BasicMember& operator=(
+ const BasicMember& other) {
+ return operator=(other.Get());
+ }
+ // Move assignment.
+ BasicMember& operator=(BasicMember&& other) noexcept {
+ operator=(other.Get());
+ other.Clear();
+ return *this;
+ }
+ // Heterogeneous move assignment.
+ template ::value>>
+ BasicMember& operator=(BasicMember&& other) noexcept {
+ operator=(other.Get());
+ other.Clear();
+ return *this;
+ }
+ // Assignment from Persistent.
+ template ::value>>
+ BasicMember& operator=(
+ const BasicPersistent&
+ other) {
+ return operator=(other.Get());
+ }
+ BasicMember& operator=(T* other) {
+ SetRawAtomic(other);
+ AssigningWriteBarrier();
+ this->CheckPointer(Get());
+ return *this;
+ }
+ BasicMember& operator=(std::nullptr_t) {
+ Clear();
+ return *this;
+ }
+ BasicMember& operator=(SentinelPointer s) {
+ SetRawAtomic(s);
+ return *this;
+ }
+
+ template
+ void Swap(BasicMember& other) {
+ T* tmp = Get();
+ *this = other;
+ other = tmp;
+ }
+
+ explicit operator bool() const { return Get(); }
+ operator T*() const { return Get(); }
+ T* operator->() const { return Get(); }
+ T& operator*() const { return *Get(); }
+
+ // CFI cast exemption to allow passing SentinelPointer through T* and support
+ // heterogeneous assignments between different Member and Persistent handles
+ // based on their actual types.
+ V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
+ // Executed by the mutator, hence non atomic load.
+ //
+ // The const_cast below removes the constness from MemberBase storage. The
+ // following static_cast re-adds any constness if specified through the
+ // user-visible template parameter T.
+ return static_cast(const_cast(MemberBase::GetRaw()));
+ }
+
+ void Clear() { SetRawAtomic(nullptr); }
+
+ T* Release() {
+ T* result = Get();
+ Clear();
+ return result;
+ }
+
+ const T** GetSlotForTesting() const {
+ return reinterpret_cast(GetRawSlot());
+ }
+
+ private:
+ const T* GetRawAtomic() const {
+ return static_cast(MemberBase::GetRawAtomic());
+ }
+
+ void InitializingWriteBarrier() const {
+ WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw());
+ }
+ void AssigningWriteBarrier() const {
+ WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw());
+ }
+
+ void ClearFromGC() const { MemberBase::ClearFromGC(); }
+
+ T* GetFromGC() const { return Get(); }
+
+ friend class cppgc::Visitor;
+ template
+ friend struct cppgc::TraceTrait;
+};
+
+template
+bool operator==(const BasicMember& member1,
+ const BasicMember& member2) {
+ return member1.Get() == member2.Get();
+}
+
+template
+bool operator!=(const BasicMember& member1,
+ const BasicMember& member2) {
+ return !(member1 == member2);
+}
+
+template
+struct IsWeak<
+ internal::BasicMember>
+ : std::true_type {};
+
+} // namespace internal
+
+/**
+ * Members are used in classes to contain strong pointers to other garbage
+ * collected objects. All Member fields of a class must be traced in the class'
+ * trace method.
+ */
+template
+using Member = internal::BasicMember;
+
+/**
+ * WeakMember is similar to Member in that it is used to point to other garbage
+ * collected objects. However instead of creating a strong pointer to the
+ * object, the WeakMember creates a weak pointer, which does not keep the
+ * pointee alive. Hence if all pointers to to a heap allocated object are weak
+ * the object will be garbage collected. At the time of GC the weak pointers
+ * will automatically be set to null.
+ */
+template
+using WeakMember = internal::BasicMember;
+
+/**
+ * UntracedMember is a pointer to an on-heap object that is not traced for some
+ * reason. Do not use this unless you know what you are doing. Keeping raw
+ * pointers to on-heap objects is prohibited unless used from stack. Pointee
+ * must be kept alive through other means.
+ */
+template
+using UntracedMember = internal::BasicMember;
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_MEMBER_H_
diff --git a/libs/android/libnode/include/node/cppgc/name-provider.h b/libs/android/libnode/include/node/cppgc/name-provider.h
new file mode 100644
index 0000000..224dd4b
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/name-provider.h
@@ -0,0 +1,65 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_
+#define INCLUDE_CPPGC_NAME_PROVIDER_H_
+
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+/**
+ * NameProvider allows for providing a human-readable name for garbage-collected
+ * objects.
+ *
+ * There's two cases of names to distinguish:
+ * a. Explicitly specified names via using NameProvider. Such names are always
+ * preserved in the system.
+ * b. Internal names that Oilpan infers from a C++ type on the class hierarchy
+ * of the object. This is not necessarily the type of the actually
+ * instantiated object.
+ *
+ * Depending on the build configuration, Oilpan may hide names, i.e., represent
+ * them with kHiddenName, of case b. to avoid exposing internal details.
+ */
+class V8_EXPORT NameProvider {
+ public:
+ /**
+ * Name that is used when hiding internals.
+ */
+ static constexpr const char kHiddenName[] = "InternalNode";
+
+ /**
+ * Name that is used in case compiler support is missing for composing a name
+ * from C++ types.
+ */
+ static constexpr const char kNoNameDeducible[] = "";
+
+ /**
+ * Indicating whether internal names are hidden or not.
+ *
+ * @returns true if C++ names should be hidden and represented by kHiddenName.
+ */
+ static constexpr bool HideInternalNames() {
+#if CPPGC_SUPPORTS_OBJECT_NAMES
+ return false;
+#else // !CPPGC_SUPPORTS_OBJECT_NAMES
+ return true;
+#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
+ }
+
+ virtual ~NameProvider() = default;
+
+ /**
+ * Specifies a name for the garbage-collected object. Such names will never
+ * be hidden, as they are explicitly specified by the user of this API.
+ *
+ * @returns a human readable name for the object.
+ */
+ virtual const char* GetHumanReadableName() const = 0;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_
diff --git a/libs/android/libnode/include/node/cppgc/object-size-trait.h b/libs/android/libnode/include/node/cppgc/object-size-trait.h
new file mode 100644
index 0000000..3579559
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/object-size-trait.h
@@ -0,0 +1,58 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
+#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
+
+#include
+
+#include "cppgc/type-traits.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+namespace internal {
+
+struct V8_EXPORT BaseObjectSizeTrait {
+ protected:
+ static size_t GetObjectSizeForGarbageCollected(const void*);
+ static size_t GetObjectSizeForGarbageCollectedMixin(const void*);
+};
+
+} // namespace internal
+
+namespace subtle {
+
+/**
+ * Trait specifying how to get the size of an object that was allocated using
+ * `MakeGarbageCollected()`. Also supports querying the size with an inner
+ * pointer to a mixin.
+ */
+template >
+struct ObjectSizeTrait;
+
+template
+struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait {
+ static_assert(sizeof(T), "T must be fully defined");
+ static_assert(IsGarbageCollectedTypeV,
+ "T must be of type GarbageCollected or GarbageCollectedMixin");
+
+ static size_t GetSize(const T& object) {
+ return GetObjectSizeForGarbageCollected(&object);
+ }
+};
+
+template
+struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait {
+ static_assert(sizeof(T), "T must be fully defined");
+
+ static size_t GetSize(const T& object) {
+ return GetObjectSizeForGarbageCollectedMixin(&object);
+ }
+};
+
+} // namespace subtle
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
diff --git a/libs/android/libnode/include/node/cppgc/persistent.h b/libs/android/libnode/include/node/cppgc/persistent.h
new file mode 100644
index 0000000..244f94c
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/persistent.h
@@ -0,0 +1,370 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_PERSISTENT_H_
+#define INCLUDE_CPPGC_PERSISTENT_H_
+
+#include
+
+#include "cppgc/internal/persistent-node.h"
+#include "cppgc/internal/pointer-policies.h"
+#include "cppgc/sentinel-pointer.h"
+#include "cppgc/source-location.h"
+#include "cppgc/type-traits.h"
+#include "cppgc/visitor.h"
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+class Visitor;
+
+namespace internal {
+
+// PersistentBase always refers to the object as const object and defers to
+// BasicPersistent on casting to the right type as needed.
+class PersistentBase {
+ protected:
+ PersistentBase() = default;
+ explicit PersistentBase(const void* raw) : raw_(raw) {}
+
+ const void* GetValue() const { return raw_; }
+ void SetValue(const void* value) { raw_ = value; }
+
+ PersistentNode* GetNode() const { return node_; }
+ void SetNode(PersistentNode* node) { node_ = node; }
+
+ // Performs a shallow clear which assumes that internal persistent nodes are
+ // destroyed elsewhere.
+ void ClearFromGC() const {
+ raw_ = nullptr;
+ node_ = nullptr;
+ }
+
+ protected:
+ mutable const void* raw_ = nullptr;
+ mutable PersistentNode* node_ = nullptr;
+
+ friend class PersistentRegionBase;
+};
+
+// The basic class from which all Persistent classes are generated.
+template
+class BasicPersistent final : public PersistentBase,
+ public LocationPolicy,
+ private WeaknessPolicy,
+ private CheckingPolicy {
+ public:
+ using typename WeaknessPolicy::IsStrongPersistent;
+ using PointeeType = T;
+
+ // Null-state/sentinel constructors.
+ BasicPersistent( // NOLINT
+ const SourceLocation& loc = SourceLocation::Current())
+ : LocationPolicy(loc) {}
+
+ BasicPersistent(std::nullptr_t, // NOLINT
+ const SourceLocation& loc = SourceLocation::Current())
+ : LocationPolicy(loc) {}
+
+ BasicPersistent( // NOLINT
+ SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
+ : PersistentBase(s), LocationPolicy(loc) {}
+
+ // Raw value constructors.
+ BasicPersistent(T* raw, // NOLINT
+ const SourceLocation& loc = SourceLocation::Current())
+ : PersistentBase(raw), LocationPolicy(loc) {
+ if (!IsValid()) return;
+ SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
+ .AllocateNode(this, &BasicPersistent::Trace));
+ this->CheckPointer(Get());
+ }
+
+ BasicPersistent(T& raw, // NOLINT
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicPersistent(&raw, loc) {}
+
+ // Copy ctor.
+ BasicPersistent(const BasicPersistent& other,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicPersistent(other.Get(), loc) {}
+
+ // Heterogeneous ctor.
+ template ::value>>
+ BasicPersistent(
+ const BasicPersistent& other,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicPersistent(other.Get(), loc) {}
+
+ // Move ctor. The heterogeneous move ctor is not supported since e.g.
+ // persistent can't reuse persistent node from weak persistent.
+ BasicPersistent(
+ BasicPersistent&& other,
+ const SourceLocation& loc = SourceLocation::Current()) noexcept
+ : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
+ if (!IsValid()) return;
+ GetNode()->UpdateOwner(this);
+ other.SetValue(nullptr);
+ other.SetNode(nullptr);
+ this->CheckPointer(Get());
+ }
+
+ // Constructor from member.
+ template ::value>>
+ BasicPersistent(
+ const internal::BasicMember& member,
+ const SourceLocation& loc = SourceLocation::Current())
+ : BasicPersistent(member.Get(), loc) {}
+
+ ~BasicPersistent() { Clear(); }
+
+ // Copy assignment.
+ BasicPersistent& operator=(const BasicPersistent& other) {
+ return operator=(other.Get());
+ }
+
+ template ::value>>
+ BasicPersistent& operator=(
+ const BasicPersistent& other) {
+ return operator=(other.Get());
+ }
+
+ // Move assignment.
+ BasicPersistent& operator=(BasicPersistent&& other) noexcept {
+ if (this == &other) return *this;
+ Clear();
+ PersistentBase::operator=(std::move(other));
+ LocationPolicy::operator=(std::move(other));
+ if (!IsValid()) return *this;
+ GetNode()->UpdateOwner(this);
+ other.SetValue(nullptr);
+ other.SetNode(nullptr);
+ this->CheckPointer(Get());
+ return *this;
+ }
+
+ // Assignment from member.
+ template ::value>>
+ BasicPersistent& operator=(
+ const internal::BasicMember& member) {
+ return operator=(member.Get());
+ }
+
+ BasicPersistent& operator=(T* other) {
+ Assign(other);
+ return *this;
+ }
+
+ BasicPersistent& operator=(std::nullptr_t) {
+ Clear();
+ return *this;
+ }
+
+ BasicPersistent& operator=(SentinelPointer s) {
+ Assign(s);
+ return *this;
+ }
+
+ explicit operator bool() const { return Get(); }
+ operator T*() const { return Get(); }
+ T* operator->() const { return Get(); }
+ T& operator*() const { return *Get(); }
+
+ // CFI cast exemption to allow passing SentinelPointer through T* and support
+ // heterogeneous assignments between different Member and Persistent handles
+ // based on their actual types.
+ V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
+ // The const_cast below removes the constness from PersistentBase storage.
+ // The following static_cast re-adds any constness if specified through the
+ // user-visible template parameter T.
+ return static_cast(const_cast(GetValue()));
+ }
+
+ void Clear() {
+ // Simplified version of `Assign()` to allow calling without a complete type
+ // `T`.
+ if (IsValid()) {
+ WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
+ SetNode(nullptr);
+ }
+ SetValue(nullptr);
+ }
+
+ T* Release() {
+ T* result = Get();
+ Clear();
+ return result;
+ }
+
+ template
+ BasicPersistent
+ To() const {
+ return BasicPersistent(static_cast(Get()));
+ }
+
+ private:
+ static void Trace(Visitor* v, const void* ptr) {
+ const auto* persistent = static_cast(ptr);
+ v->TraceRoot(*persistent, persistent->Location());
+ }
+
+ bool IsValid() const {
+ // Ideally, handling kSentinelPointer would be done by the embedder. On the
+ // other hand, having Persistent aware of it is beneficial since no node
+ // gets wasted.
+ return GetValue() != nullptr && GetValue() != kSentinelPointer;
+ }
+
+ void Assign(T* ptr) {
+ if (IsValid()) {
+ if (ptr && ptr != kSentinelPointer) {
+ // Simply assign the pointer reusing the existing node.
+ SetValue(ptr);
+ this->CheckPointer(ptr);
+ return;
+ }
+ WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
+ SetNode(nullptr);
+ }
+ SetValue(ptr);
+ if (!IsValid()) return;
+ SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
+ .AllocateNode(this, &BasicPersistent::Trace));
+ this->CheckPointer(Get());
+ }
+
+ void ClearFromGC() const {
+ if (IsValid()) {
+ WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
+ PersistentBase::ClearFromGC();
+ }
+ }
+
+ // Set Get() for details.
+ V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
+ T* GetFromGC() const {
+ return static_cast(const_cast(GetValue()));
+ }
+
+ friend class cppgc::Visitor;
+};
+
+template
+bool operator==(const BasicPersistent& p1,
+ const BasicPersistent& p2) {
+ return p1.Get() == p2.Get();
+}
+
+template
+bool operator!=(const BasicPersistent& p1,
+ const BasicPersistent& p2) {
+ return !(p1 == p2);
+}
+
+template
+bool operator==(
+ const BasicPersistent&
+ p,
+ const BasicMember& m) {
+ return p.Get() == m.Get();
+}
+
+template
+bool operator!=(
+ const BasicPersistent&
+ p,
+ const BasicMember& m) {
+ return !(p == m);
+}
+
+template
+bool operator==(
+ const BasicMember& m,
+ const BasicPersistent&
+ p) {
+ return m.Get() == p.Get();
+}
+
+template
+bool operator!=(
+ const BasicMember& m,
+ const BasicPersistent&
+ p) {
+ return !(m == p);
+}
+
+template
+struct IsWeak> : std::true_type {};
+} // namespace internal
+
+/**
+ * Persistent is a way to create a strong pointer from an off-heap object to
+ * another on-heap object. As long as the Persistent handle is alive the GC will
+ * keep the object pointed to alive. The Persistent handle is always a GC root
+ * from the point of view of the GC. Persistent must be constructed and
+ * destructed in the same thread.
+ */
+template
+using Persistent =
+ internal::BasicPersistent;
+
+/**
+ * WeakPersistent is a way to create a weak pointer from an off-heap object to
+ * an on-heap object. The pointer is automatically cleared when the pointee gets
+ * collected. WeakPersistent must be constructed and destructed in the same
+ * thread.
+ */
+template
+using WeakPersistent =
+ internal::BasicPersistent;
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_PERSISTENT_H_
diff --git a/libs/android/libnode/include/node/cppgc/platform.h b/libs/android/libnode/include/node/cppgc/platform.h
new file mode 100644
index 0000000..5d5f879
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/platform.h
@@ -0,0 +1,156 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_PLATFORM_H_
+#define INCLUDE_CPPGC_PLATFORM_H_
+
+#include
+
+#include "cppgc/source-location.h"
+#include "v8-platform.h" // NOLINT(build/include_directory)
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+
+// TODO(v8:10346): Create separate includes for concepts that are not
+// V8-specific.
+using IdleTask = v8::IdleTask;
+using JobHandle = v8::JobHandle;
+using JobDelegate = v8::JobDelegate;
+using JobTask = v8::JobTask;
+using PageAllocator = v8::PageAllocator;
+using Task = v8::Task;
+using TaskPriority = v8::TaskPriority;
+using TaskRunner = v8::TaskRunner;
+using TracingController = v8::TracingController;
+
+/**
+ * Platform interface used by Heap. Contains allocators and executors.
+ */
+class V8_EXPORT Platform {
+ public:
+ virtual ~Platform() = default;
+
+ /**
+ * Returns the allocator used by cppgc to allocate its heap and various
+ * support structures.
+ */
+ virtual PageAllocator* GetPageAllocator() = 0;
+
+ /**
+ * Monotonically increasing time in seconds from an arbitrary fixed point in
+ * the past. This function is expected to return at least
+ * millisecond-precision values. For this reason,
+ * it is recommended that the fixed point be no further in the past than
+ * the epoch.
+ **/
+ virtual double MonotonicallyIncreasingTime() = 0;
+
+ /**
+ * Foreground task runner that should be used by a Heap.
+ */
+ virtual std::shared_ptr GetForegroundTaskRunner() {
+ return nullptr;
+ }
+
+ /**
+ * Posts `job_task` to run in parallel. Returns a `JobHandle` associated with
+ * the `Job`, which can be joined or canceled.
+ * This avoids degenerate cases:
+ * - Calling `CallOnWorkerThread()` for each work item, causing significant
+ * overhead.
+ * - Fixed number of `CallOnWorkerThread()` calls that split the work and
+ * might run for a long time. This is problematic when many components post
+ * "num cores" tasks and all expect to use all the cores. In these cases,
+ * the scheduler lacks context to be fair to multiple same-priority requests
+ * and/or ability to request lower priority work to yield when high priority
+ * work comes in.
+ * A canonical implementation of `job_task` looks like:
+ * \code
+ * class MyJobTask : public JobTask {
+ * public:
+ * MyJobTask(...) : worker_queue_(...) {}
+ * // JobTask implementation.
+ * void Run(JobDelegate* delegate) override {
+ * while (!delegate->ShouldYield()) {
+ * // Smallest unit of work.
+ * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe.
+ * if (!work_item) return;
+ * ProcessWork(work_item);
+ * }
+ * }
+ *
+ * size_t GetMaxConcurrency() const override {
+ * return worker_queue_.GetSize(); // Thread safe.
+ * }
+ * };
+ *
+ * // ...
+ * auto handle = PostJob(TaskPriority::kUserVisible,
+ * std::make_unique(...));
+ * handle->Join();
+ * \endcode
+ *
+ * `PostJob()` and methods of the returned JobHandle/JobDelegate, must never
+ * be called while holding a lock that could be acquired by `JobTask::Run()`
+ * or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This
+ * is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding
+ * internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock
+ * (B) if that lock is *never* held while calling back into `JobHandle` from
+ * any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or
+ * `JobTask::GetMaxConcurrency()` may be invoked synchronously from
+ * `JobHandle` (B=>JobHandle::foo=>B deadlock).
+ *
+ * A sufficient `PostJob()` implementation that uses the default Job provided
+ * in libplatform looks like:
+ * \code
+ * std::unique_ptr PostJob(
+ * TaskPriority priority, std::unique_ptr job_task) override {
+ * return std::make_unique(
+ * std::make_shared(
+ * this, std::move(job_task), kNumThreads));
+ * }
+ * \endcode
+ */
+ virtual std::unique_ptr PostJob(
+ TaskPriority priority, std::unique_ptr job_task) {
+ return nullptr;
+ }
+
+ /**
+ * Returns an instance of a `TracingController`. This must be non-nullptr. The
+ * default implementation returns an empty `TracingController` that consumes
+ * trace data without effect.
+ */
+ virtual TracingController* GetTracingController();
+};
+
+/**
+ * Process-global initialization of the garbage collector. Must be called before
+ * creating a Heap.
+ *
+ * Can be called multiple times when paired with `ShutdownProcess()`.
+ *
+ * \param page_allocator The allocator used for maintaining meta data. Must not
+ * change between multiple calls to InitializeProcess.
+ */
+V8_EXPORT void InitializeProcess(PageAllocator* page_allocator);
+
+/**
+ * Must be called after destroying the last used heap. Some process-global
+ * metadata may not be returned and reused upon a subsequent
+ * `InitializeProcess()` call.
+ */
+V8_EXPORT void ShutdownProcess();
+
+namespace internal {
+
+V8_EXPORT void Fatal(const std::string& reason = std::string(),
+ const SourceLocation& = SourceLocation::Current());
+
+} // namespace internal
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_PLATFORM_H_
diff --git a/libs/android/libnode/include/node/cppgc/prefinalizer.h b/libs/android/libnode/include/node/cppgc/prefinalizer.h
new file mode 100644
index 0000000..51f2eac
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/prefinalizer.h
@@ -0,0 +1,75 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_PREFINALIZER_H_
+#define INCLUDE_CPPGC_PREFINALIZER_H_
+
+#include "cppgc/internal/compiler-specific.h"
+#include "cppgc/liveness-broker.h"
+
+namespace cppgc {
+
+namespace internal {
+
+class V8_EXPORT PrefinalizerRegistration final {
+ public:
+ using Callback = bool (*)(const cppgc::LivenessBroker&, void*);
+
+ PrefinalizerRegistration(void*, Callback);
+
+ void* operator new(size_t, void* location) = delete;
+ void* operator new(size_t) = delete;
+};
+
+} // namespace internal
+
+/**
+ * Macro must be used in the private section of `Class` and registers a
+ * prefinalization callback `void Class::PreFinalizer()`. The callback is
+ * invoked on garbage collection after the collector has found an object to be
+ * dead.
+ *
+ * Callback properties:
+ * - The callback is invoked before a possible destructor for the corresponding
+ * object.
+ * - The callback may access the whole object graph, irrespective of whether
+ * objects are considered dead or alive.
+ * - The callback is invoked on the same thread as the object was created on.
+ *
+ * Example:
+ * \code
+ * class WithPrefinalizer : public GarbageCollected {
+ * CPPGC_USING_PRE_FINALIZER(WithPrefinalizer, Dispose);
+ *
+ * public:
+ * void Trace(Visitor*) const {}
+ * void Dispose() { prefinalizer_called = true; }
+ * ~WithPrefinalizer() {
+ * // prefinalizer_called == true
+ * }
+ * private:
+ * bool prefinalizer_called = false;
+ * };
+ * \endcode
+ */
+#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \
+ public: \
+ static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \
+ void* object) { \
+ static_assert(cppgc::IsGarbageCollectedOrMixinTypeV, \
+ "Only garbage collected objects can have prefinalizers"); \
+ Class* self = static_cast(object); \
+ if (liveness_broker.IsHeapObjectAlive(self)) return false; \
+ self->PreFinalizer(); \
+ return true; \
+ } \
+ \
+ private: \
+ CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \
+ prefinalizer_dummy_{this, Class::InvokePreFinalizer}; \
+ static_assert(true, "Force semicolon.")
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_PREFINALIZER_H_
diff --git a/libs/android/libnode/include/node/cppgc/process-heap-statistics.h b/libs/android/libnode/include/node/cppgc/process-heap-statistics.h
new file mode 100644
index 0000000..774cc92
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/process-heap-statistics.h
@@ -0,0 +1,36 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
+#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
+
+#include
+#include
+
+#include "v8config.h" // NOLINT(build/include_directory)
+
+namespace cppgc {
+namespace internal {
+class ProcessHeapStatisticsUpdater;
+} // namespace internal
+
+class V8_EXPORT ProcessHeapStatistics final {
+ public:
+ static size_t TotalAllocatedObjectSize() {
+ return total_allocated_object_size_.load(std::memory_order_relaxed);
+ }
+ static size_t TotalAllocatedSpace() {
+ return total_allocated_space_.load(std::memory_order_relaxed);
+ }
+
+ private:
+ static std::atomic_size_t total_allocated_space_;
+ static std::atomic_size_t total_allocated_object_size_;
+
+ friend class internal::ProcessHeapStatisticsUpdater;
+};
+
+} // namespace cppgc
+
+#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
diff --git a/libs/android/libnode/include/node/cppgc/sentinel-pointer.h b/libs/android/libnode/include/node/cppgc/sentinel-pointer.h
new file mode 100644
index 0000000..b049d1a
--- /dev/null
+++ b/libs/android/libnode/include/node/cppgc/sentinel-pointer.h
@@ -0,0 +1,32 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_
+#define INCLUDE_CPPGC_SENTINEL_POINTER_H_
+
+#include
+
+namespace cppgc {
+namespace internal {
+
+// Special tag type used to denote some sentinel member. The semantics of the
+// sentinel is defined by the embedder.
+struct SentinelPointer {
+ template