diff --git a/.github/workflows/npm_release.yml b/.github/workflows/npm_release.yml index 9f4da2a86..43a4c76b7 100644 --- a/.github/workflows/npm_release.yml +++ b/.github/workflows/npm_release.yml @@ -8,15 +8,15 @@ on: env: NPM_TAG: "next" EMULATOR_NAME: "runtime-emu" - NDK_VERSION: r21b - ANDROID_API: 29 + NDK_VERSION: r27 + ANDROID_API: 33 ANDROID_ABI: x86_64 - NDK_ARCH: darwin-x86_64 + NDK_ARCH: darwin jobs: build: name: Build - runs-on: macos-latest + runs-on: macos-13 outputs: npm_version: ${{ steps.npm_version_output.outputs.NPM_VERSION }} npm_tag: ${{ steps.npm_version_output.outputs.NPM_TAG }} @@ -27,12 +27,12 @@ jobs: submodules: true - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: "https://registry.npmjs.org" - uses: actions/setup-java@v3 with: distribution: "temurin" - java-version: "17" + java-version: "21" cache: gradle - name: Setup Android SDK uses: android-actions/setup-android@v2 @@ -73,13 +73,19 @@ jobs: - name: Build npm package run: ./gradlew -PgitCommitVersion=${{ github.sha }} -PnoCCache --stacktrace - name: Upload npm package artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: npm-package path: dist/nativescript-android-${{steps.npm_version_output.outputs.NPM_VERSION}}.tgz + - name: Upload debug symbols + uses: actions/upload-artifact@v4 + with: + name: debug-symbols + path: test-app/runtime/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib/* + test: name: Test - runs-on: macos-latest + runs-on: macos-13 needs: build steps: - uses: actions/checkout@v3 @@ -87,12 +93,12 @@ jobs: submodules: true - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: "https://registry.npmjs.org" - uses: actions/setup-java@v3 with: distribution: "temurin" - java-version: "17" + java-version: "21" cache: gradle - name: Setup Android SDK uses: android-actions/setup-android@v2 @@ -138,9 +144,9 @@ jobs: steps: - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: "https://registry.npmjs.org" - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: npm-package path: dist @@ -167,17 +173,24 @@ jobs: fetch-depth: 0 - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: Setup run: npm install - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: npm-package path: dist + - uses: actions/download-artifact@v4 + with: + name: debug-symbols + path: dist/debug-symbols + - name: Zip debug symbols + working-directory: dist/debug-symbols + run: zip -r debug-symbols.zip . - name: Partial Changelog run: npx conventional-changelog -p angular -r2 > body.md - uses: ncipollo/release-action@v1 with: - artifacts: "dist/nativescript-android-*.tgz" + artifacts: "dist/nativescript-android-*.tgz,dist/debug-symbols/debug-symbols.zip" bodyFile: "body.md" prerelease: ${{needs.build.outputs.npm_tag != 'latest'}} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index a2c844c83..de0f75728 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -4,16 +4,16 @@ on: env: NPM_TAG: "pr" EMULATOR_NAME: "runtime-emu" - NDK_VERSION: r21b - ANDROID_API: 29 + NDK_VERSION: r27 + ANDROID_API: 33 ANDROID_ABI: x86_64 - NDK_ARCH: darwin-x86_64 + NDK_ARCH: darwin jobs: build: name: Build - runs-on: macos-latest + runs-on: macos-13 outputs: npm_version: ${{ steps.npm_version_output.outputs.NPM_VERSION }} npm_tag: ${{ steps.npm_version_output.outputs.NPM_TAG }} @@ -24,12 +24,12 @@ jobs: submodules: true - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: "https://registry.npmjs.org" - uses: actions/setup-java@v3 with: distribution: "temurin" - java-version: "17" + java-version: "21" cache: gradle - name: Setup Android SDK uses: android-actions/setup-android@v2 @@ -70,13 +70,18 @@ jobs: - name: Build npm package run: ./gradlew -PgitCommitVersion=${{ github.sha }} -PnoCCache --stacktrace - name: Upload npm package artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: npm-package path: dist/nativescript-android-${{steps.npm_version_output.outputs.NPM_VERSION}}.tgz + - name: Upload debug symbols + uses: actions/upload-artifact@v4 + with: + name: debug-symbols + path: test-app/runtime/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib/* test: name: Test - runs-on: macos-latest + runs-on: macos-13 needs: build steps: - uses: actions/checkout@v3 @@ -84,12 +89,12 @@ jobs: submodules: true - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: "https://registry.npmjs.org" - uses: actions/setup-java@v3 with: distribution: "temurin" - java-version: "17" + java-version: "21" cache: gradle - name: Setup Android SDK uses: android-actions/setup-android@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a616c1b..4b6700151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,161 @@ +# [8.9.0](https://github.com/NativeScript/android/compare/v8.8.6...v8.9.0) (2025-02-26) + + +### Bug Fixes + +* inner type should net be set when companion object is defined as function ([#1831](https://github.com/NativeScript/android/issues/1831)) ([e293636](https://github.com/NativeScript/android/commit/e293636ed1e9277d608e3102b404f94539404fdf)) + + +### Features + +* Ada 3.1.1 ([3633aed](https://github.com/NativeScript/android/commit/3633aed8913c7b93757909a569bfb8ab225add13)) +* ada v3 ([#1830](https://github.com/NativeScript/android/issues/1830)) ([b31fc5f](https://github.com/NativeScript/android/commit/b31fc5f7144b873981b8c7201d72baf26a6e79bc)) +* NDK 27 and Support for Java 21 ([#1819](https://github.com/NativeScript/android/issues/1819)) ([bec401c](https://github.com/NativeScript/android/commit/bec401c918942443bccab4e697cea2ccb843e603)) +* support 16 KB page sizes, gradle 8.5 ([#1818](https://github.com/NativeScript/android/issues/1818)) ([3423e6f](https://github.com/NativeScript/android/commit/3423e6ff05c5340f92eec46f8c8e996d78403860)) + + +### Performance Improvements + +* optimizations around generating JS classes from Metadata ([#1824](https://github.com/NativeScript/android/issues/1824)) ([f290ed2](https://github.com/NativeScript/android/commit/f290ed26da315ddefb56fa1acd212c6242ab976b)) + + + +## [8.8.6](https://github.com/NativeScript/android/compare/v8.8.5...v8.8.6) (2024-10-28) + + +### Bug Fixes + +* `exit(0)` causes ANR due to destroyed mutex ([#1820](https://github.com/NativeScript/android/issues/1820)) ([94ddb15](https://github.com/NativeScript/android/commit/94ddb159ccf368edebce76a8aa01d141d7297b1a)) +* gradle error when compileSdk or targetSdk is provided ([#1825](https://github.com/NativeScript/android/issues/1825)) ([a983931](https://github.com/NativeScript/android/commit/a983931cf5e9fcc7966a98a2f0ec4e24e040af5e)) +* **URL:** allow undefined 2nd args ([#1826](https://github.com/NativeScript/android/issues/1826)) ([2bab8f5](https://github.com/NativeScript/android/commit/2bab8f5be85c8764faafef4d6374dc8cfd257613)) + + + +## [8.8.5](https://github.com/NativeScript/android/compare/v8.8.4...v8.8.5) (2024-09-30) + + +### Bug Fixes + +* prevent metadata offset overflow into array space and convert shorts to uints before addition ([9cfc349](https://github.com/NativeScript/android/commit/9cfc3493017243948b043a51f68b7c7bcab1e6b9)) + + + +## [8.8.4](https://github.com/NativeScript/android/compare/v8.8.3...v8.8.4) (2024-09-06) + + +### Bug Fixes + +* ensure same mtime for js and code cache to prevent loading old code caches ([#1822](https://github.com/NativeScript/android/issues/1822)) ([3d6e101](https://github.com/NativeScript/android/commit/3d6e10115227ad556e5bbe1764217716ab5bdac7)) + + + +## [8.8.3](https://github.com/NativeScript/android/compare/v8.8.2...v8.8.3) (2024-09-02) + + +### Bug Fixes + +* generate correct metadata when overflowing signed short values ([#1821](https://github.com/NativeScript/android/issues/1821)) ([c9fac4b](https://github.com/NativeScript/android/commit/c9fac4b19a952d4df651d3d6a8b0fa9c50f7c7db)) + + + +## [8.8.2](https://github.com/NativeScript/android/compare/v8.8.1...v8.8.2) (2024-07-22) + + +### Bug Fixes + +* config with multiple bundle ids ([#1816](https://github.com/NativeScript/android/issues/1816)) ([cdcfee2](https://github.com/NativeScript/android/commit/cdcfee266617472ac7f3ac59742b858ad093e46b)) + + + +## [8.8.1](https://github.com/NativeScript/android/compare/v8.8.0...v8.8.1) (2024-07-10) + + +### Features + +* Ada 2.9 ([#1814](https://github.com/NativeScript/android/issues/1814)) ([91accf9](https://github.com/NativeScript/android/commit/91accf9be1caf9ad2accb80bf9aca18efe4dd75a)) + + + +# [8.8.0](https://github.com/NativeScript/android/compare/v8.7.0...v8.8.0) (2024-07-09) + + +### Bug Fixes + +* correctly load ts_helpers.js in workers ([#1798](https://github.com/NativeScript/android/issues/1798)) ([31f8501](https://github.com/NativeScript/android/commit/31f8501bb902815cfed8e1cd123fe8b6de2cb757)) + + +### Features + +* Kotlin 2 + Gradle 8+ ([#1812](https://github.com/NativeScript/android/issues/1812)) ([d4b7164](https://github.com/NativeScript/android/commit/d4b716427934ebb4387a04842561d5b5d0e1fa3d)) + + + +# [8.7.0](https://github.com/NativeScript/android/compare/v8.7.0-rc.3...v8.7.0) (2024-04-08) + + + +# [8.7.0-rc.3](https://github.com/NativeScript/android/compare/v8.6.2...v8.7.0-rc.3) (2024-04-08) + + +### Bug Fixes + +* devtools namespace usage ([#1810](https://github.com/NativeScript/android/issues/1810)) ([5aaac57](https://github.com/NativeScript/android/commit/5aaac5788ff9abf1c043817e87c8e03eb61907c0)) +* dts-generator.jar path ([1120a32](https://github.com/NativeScript/android/commit/1120a3258d53f83b7b4dfe7e505234e2b0d6cd2b)) +* inspector and globals ([#1811](https://github.com/NativeScript/android/issues/1811)) ([79ebd18](https://github.com/NativeScript/android/commit/79ebd18f308cd86fa98784f14b5c3f5ac39d8c5f)) + + +### Features + +* bump ndk to r23c ([#1803](https://github.com/NativeScript/android/issues/1803)) ([3894959](https://github.com/NativeScript/android/commit/3894959e0b4fe31f61cfd9fa70d5e2b04a0f36ac)) +* devtools element/network inspectors ([#1808](https://github.com/NativeScript/android/issues/1808)) ([1470796](https://github.com/NativeScript/android/commit/1470796dc506f0d01e94fe117119dc217ff8c909)) +* migrate to faster maps and use runtime context ([#1793](https://github.com/NativeScript/android/issues/1793)) ([b248dc4](https://github.com/NativeScript/android/commit/b248dc4038d0c1a6af420447c713bc968431f97e)) +* update libzip to 1.10.1 ([#1805](https://github.com/NativeScript/android/issues/1805)) ([ee2e3e0](https://github.com/NativeScript/android/commit/ee2e3e0b87caf3cff4784f1464dd51b2923c6861)) +* use node module bindings like the iOS runtime ([#1795](https://github.com/NativeScript/android/issues/1795)) ([643958b](https://github.com/NativeScript/android/commit/643958b6a4c3698567edde3fd03052873b2644dc)) +* **WinterCG:** URL & URLSearchParams ([#1801](https://github.com/NativeScript/android/issues/1801)) ([4f3a0d7](https://github.com/NativeScript/android/commit/4f3a0d7f2de5f899779bd0fe9081390e6c4d24b2)) + + +### Reverts + +* Version.h changes ([9faa25d](https://github.com/NativeScript/android/commit/9faa25dda197d3da4f694ea59208309bb02e529c)) + + + +## [8.6.2](https://github.com/NativeScript/android/compare/v8.6.1...v8.6.2) (2023-10-10) + + + +## [8.6.1](https://github.com/NativeScript/android/compare/v8.6.0...v8.6.1) (2023-10-10) + + +### Bug Fixes + +* copy drawables ([4ff92cb](https://github.com/NativeScript/android/commit/4ff92cb32a954be4c3d32c302e301cef0a4b72a6)) + + + +# [8.6.0](https://github.com/NativeScript/android/compare/v8.5.3...v8.6.0) (2023-10-06) + + +### Bug Fixes + +* make jar files readonly prior to loading ([#1790](https://github.com/NativeScript/android/issues/1790)) ([2bcdaf0](https://github.com/NativeScript/android/commit/2bcdaf01fb850db4a982c22c2d792f9493a2a7fa)) +* only use project jar files if they are linked ([d23ca94](https://github.com/NativeScript/android/commit/d23ca94ba7c660b26224c57ba6f22085aa99f95c)) +* revert namespace change as to not break existing projects ([8b7b59d](https://github.com/NativeScript/android/commit/8b7b59d23d926b696bde3c1031cf3a842a24133d)) + + +### Features + +* improved error activity ui ([#1776](https://github.com/NativeScript/android/issues/1776)) ([ee3e354](https://github.com/NativeScript/android/commit/ee3e354f1bec89268daf93086aa6dd24898677b9)) +* upgrade client gradle version ([c778c0d](https://github.com/NativeScript/android/commit/c778c0d238c4ba44390f786ba06ab8e51ffb2c97)) + +## [8.5.4](https://github.com/NativeScript/android/compare/v8.5.3...v8.5.4) (2023-09-27) + + +### Bug Fixes + +* make jar files readonly prior to loading ([#1790](https://github.com/NativeScript/android/issues/1790)) ([14a932a](https://github.com/NativeScript/android/commit/14a932ad2d62c94f2f4e139125835da760dcdd58)) + + ## [8.5.3](https://github.com/NativeScript/android/compare/v8.5.2...v8.5.3) (2023-09-22) diff --git a/build.gradle b/build.gradle index 84ac9eb77..93be4ace6 100644 --- a/build.gradle +++ b/build.gradle @@ -265,7 +265,7 @@ task copyFilesToProjectTemeplate { into "$DIST_FRAMEWORK_PATH/build-tools" } copy { - from "$BUILD_TOOLS_PATH/android-dts-generator/build/libs/dts-generator.jar" + from "$BUILD_TOOLS_PATH/android-dts-generator/dts-generator/build/libs/dts-generator.jar" into "$DIST_FRAMEWORK_PATH/build-tools" } copy { diff --git a/build.sh b/build.sh index b176b1195..2f42b49c9 100755 --- a/build.sh +++ b/build.sh @@ -50,33 +50,34 @@ fi ./gradlew runSbgTests for emulator in $listOfEmulators; do - echo "Start emulator $emulator" - $ANDROID_HOME/emulator/emulator -avd ${emulator} -verbose -wipe-data -gpu on& - find ~/.android/avd/${emulator}.avd -type f -name 'config.ini' -exec cat {} + + echo "Start emulator $emulator" + $ANDROID_HOME/emulator/emulator -avd ${emulator} -verbose -wipe-data -gpu on& + find ~/.android/avd/${emulator}.avd -type f -name 'config.ini' -exec cat {} + - echo "Run Android Runtime unit tests for $emulator" - $ANDROID_HOME/platform-tools/adb wait-for-device - $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat -c - $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat > consoleLog.txt& - $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat > consoleLog$emulator.txt& + echo "Run Android Runtime unit tests for $emulator" + $ANDROID_HOME/platform-tools/adb wait-for-device + $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat -c + $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat > consoleLog.txt& + $ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat > consoleLog$emulator.txt& - if [ "$1" != 'unit_tests_only' ]; then - ./gradlew runtests - else - ./gradlew runtests -PonlyX86 - fi + if [ "$1" != 'unit_tests_only' ]; then + ./gradlew runtests + else + ./gradlew runtests -PonlyX86 + fi - echo "Rename unit test result" - ( - cd ./test-app/dist - mv android_unit_test_results.xml $emulator.xml - ) + echo "Rename unit test result" + ( + cd ./test-app/dist + mv android_unit_test_results.xml $emulator.xml + ) - echo "Stopping running emulators" - for KILLPID in `ps ax | grep 'emulator' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done - for KILLPID in `ps ax | grep 'qemu' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done - for KILLPID in `ps ax | grep 'adb' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done + echo "Stopping running emulators" + for KILLPID in `ps ax | grep 'emulator' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done + for KILLPID in `ps ax | grep 'qemu' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done + for KILLPID in `ps ax | grep 'adb' | grep -v 'grep' | awk ' { print $1;}'`; do kill -9 $KILLPID; done done echo $cwd cd $cwd + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f..2c3521197 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 070cb702f..09523c0e5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6c..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +82,12 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +134,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index f127cfd49..9d21a2183 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -26,6 +28,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -42,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/package.json b/package.json index 1f36e90ab..60a7bd8fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@nativescript/android", "description": "NativeScript for Android using v8", - "version": "8.6.2", + "version": "8.9.1", "repository": { "type": "git", "url": "https://github.com/NativeScript/android.git" @@ -10,20 +10,20 @@ "**/*" ], "version_info": { - "v8": "8.3.110.9", - "gradle": "7.6", - "gradleAndroid": "7.4.2", - "ndk": "r21", - "ndkApiLevel": "22", - "minSdk": "17", - "compileSdk": "32", - "buildTools": "32.0.0", - "kotlin": "1.7.10" + "v8": "10.3.22.0", + "gradle": "8.7", + "gradleAndroid": "8.5.0", + "ndk": "r27", + "ndkApiLevel": "21", + "minSdk": "21", + "compileSdk": "35", + "buildTools": "35.0.0", + "kotlin": "2.0.0" }, "// this gradle key is here for backwards compatibility - we'll phase it out slowly...": "", "gradle": { - "version": "7.6", - "android": "7.4.2" + "version": "8.7", + "android": "8.5.0" }, "scripts": { "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", diff --git a/test-app/app/build.gradle b/test-app/app/build.gradle index be0641b55..ec5aea981 100644 --- a/test-app/app/build.gradle +++ b/test-app/app/build.gradle @@ -20,9 +20,8 @@ * -PappResourcesPath=[app_resources_path] */ - -import groovy.io.FileType import groovy.json.JsonSlurper +import groovy.xml.XmlSlurper import org.apache.commons.io.FileUtils import javax.inject.Inject @@ -30,26 +29,17 @@ import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardCopyOption import java.security.MessageDigest - import java.util.jar.JarEntry import java.util.jar.JarFile import static org.gradle.internal.logging.text.StyledTextOutput.Style -import java.util.stream.Collectors; -import java.util.stream.Stream; - apply plugin: "com.android.application" apply from: "gradle-helpers/BuildToolTask.gradle" apply from: "gradle-helpers/CustomExecutionLogger.gradle" apply from: "gradle-helpers/AnalyticsCollector.gradle" - -def enableKotlin = (project.hasProperty("useKotlin") && project.useKotlin == "true") - -if (enableKotlin) { - apply plugin: 'kotlin-android' - apply plugin: 'kotlin-parcelize' -} +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-parcelize' def onlyX86 = project.hasProperty("onlyX86") if (onlyX86) { @@ -75,6 +65,7 @@ def SBG_BINDINGS_NAME = "sbg-bindings.txt" def SBG_INTERFACE_NAMES = "sbg-interface-names.txt" def INPUT_JS_DIR = "$projectDir/src/main/assets/app" def OUTPUT_JAVA_DIR = "$projectDir/src/main/java" +def APP_DIR = "$projectDir/src/main/assets/app" //metadata generator def MDG_OUTPUT_DIR = "mdg-output-dir.txt" @@ -86,9 +77,9 @@ def METADATA_JAVA_OUT = "mdg-java-out.txt" def pluginsJarLibraries = new LinkedList() def allJarLibraries = new LinkedList() -def computeKotlinVersion = { -> project.hasProperty("kotlinVersion") ? kotlinVersion : "${ns_default_kotlin_version}" } -def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk : NS_DEFAULT_COMPILE_SDK_VERSION as int } -def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk : NS_DEFAULT_COMPILE_SDK_VERSION as int } +def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk as int : NS_DEFAULT_COMPILE_SDK_VERSION as int } +def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk as int : NS_DEFAULT_COMPILE_SDK_VERSION as int } +def computeMinSdkVersion = { -> project.hasProperty("minSdk") ? minSdk : NS_DEFAULT_MIN_SDK_VERSION as int } def computeBuildToolsVersion = { -> project.hasProperty("buildToolsVersion") ? buildToolsVersion : NS_DEFAULT_BUILD_TOOLS_VERSION as String } @@ -98,7 +89,7 @@ def enableVerboseMDG = project.gradle.startParameter.logLevel.name() == 'DEBUG' def analyticsFilePath = "$rootDir/analytics/build-statistics.json" def analyticsCollector = project.ext.AnalyticsCollector.withOutputPath(analyticsFilePath) if (enableAnalytics) { - analyticsCollector.markUseKotlinPropertyInApp(enableKotlin) + analyticsCollector.markUseKotlinPropertyInApp(true) analyticsCollector.writeAnalyticsFile() } @@ -185,26 +176,52 @@ def setAppIdentifier = { -> if (appIdentifier) { project.ext.nsApplicationIdentifier = appIdentifier android.defaultConfig.applicationId = appIdentifier + android.namespace = appIdentifier + } + } +} + +def computeNamespace = { -> + def appPackageJsonFile = file("${APP_DIR}/$PACKAGE_JSON") + + if (appPackageJsonFile.exists()) { + def content = appPackageJsonFile.getText("UTF-8") + + def jsonSlurper = new JsonSlurper() + def packageJsonMap = jsonSlurper.parseText(content) + + def appIdentifier = "" + + if (packageJsonMap) { + if (packageJsonMap.android && packageJsonMap.android.id) { + appIdentifier = packageJsonMap.android.id + } else if (packageJsonMap.id) { + appIdentifier = packageJsonMap.id + } + } + + if (appIdentifier) { + return appIdentifier } } + return "com.tns.testapplication" } android { + namespace computeNamespace() applyBeforePluginGradleConfiguration() - if (enableKotlin) { - kotlinOptions { - jvmTarget = '1.8' - } + kotlinOptions { + jvmTarget = '17' } - compileSdkVersion computeCompileSdkVersion() - buildToolsVersion computeBuildToolsVersion() + compileSdk computeCompileSdkVersion() + buildToolsVersion = computeBuildToolsVersion() defaultConfig { def manifest = new XmlSlurper().parse(file(android.sourceSets.main.manifest.srcFile)) - def minSdkVer = manifest."uses-sdk"."@android:minSdkVersion".text() ?: NS_DEFAULT_MIN_SDK_VERSION + def minSdkVer = manifest."uses-sdk"."@android:minSdkVersion".text() ?: computeMinSdkVersion() minSdkVersion minSdkVer targetSdkVersion computeTargetSdkVersion() ndk { @@ -217,8 +234,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } sourceSets.main { @@ -252,12 +269,12 @@ android { applyAppGradleConfiguration() def initializeMergedAssetsOutputPath = { -> - android.applicationVariants.all { variant -> + android.applicationVariants.configureEach { variant -> if (variant.buildType.name == project.selectedBuildType) { def task if (variant.metaClass.respondsTo(variant, "getMergeAssetsProvider")) { def provider = variant.getMergeAssetsProvider() - task = provider.get(); + task = provider.get() } else { // fallback for older android gradle plugin versions task = variant.getMergeAssets() @@ -265,7 +282,7 @@ android { for (File file : task.getOutputs().getFiles()) { if (!file.getPath().contains("${File.separator}incremental${File.separator}")) { project.ext.mergedAssetsOutputPath = file.getPath() - break; + break } } } @@ -395,18 +412,13 @@ dependencies { implementation project(':runtime') } - def kotlinVersion = computeKotlinVersion() - if (enableKotlin) { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" - } - } //////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// CONFIGURATION PHASE ////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// -task addDependenciesFromNativeScriptPlugins { +task 'addDependenciesFromNativeScriptPlugins' { nativescriptDependencies.each { dep -> def aarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.aar"]) aarFiles.each { aarFile -> @@ -427,7 +439,7 @@ task addDependenciesFromNativeScriptPlugins { } } -task addDependenciesFromAppResourcesLibraries { +task 'addDependenciesFromAppResourcesLibraries' { def appResourcesPath = getAppResourcesPath() def appResourcesLibraries = file("$appResourcesPath/Android/libs") if (appResourcesLibraries.exists()) { @@ -451,47 +463,20 @@ task addDependenciesFromAppResourcesLibraries { } if (failOnCompilationWarningsEnabled()) { - tasks.withType(JavaCompile) { + tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:all' << "-Werror" options.deprecation = true } } -tasks.whenTaskAdded({ DefaultTask currentTask -> - if (currentTask =~ /generate.+BuildConfig/) { - currentTask.finalizedBy(extractAllJars) - extractAllJars.finalizedBy(collectAllJars) - } - if (currentTask =~ /compile.+JavaWithJavac/) { - currentTask.dependsOn(runSbg) - currentTask.finalizedBy(buildMetadata) - } - - - if (currentTask =~ /compile.+Kotlin.+/) { - currentTask.dependsOn(runSbg) - currentTask.finalizedBy(buildMetadata) - } - - if (currentTask =~ /merge.*Assets/) { - currentTask.dependsOn(buildMetadata) - } - // ensure buildMetadata is done before R8 to allow custom proguard from metadata - if (currentTask =~ /minify.*WithR8/) { - currentTask.dependsOn(buildMetadata) - } - if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) { - currentTask.finalizedBy("validateAppIdMatch") - } -}) //////////////////////////////////////////////////////////////////////////////////// -///////////////////////////// EXECUTUION PHASE ///////////////////////////////////// +///////////////////////////// EXECUTION PHASE ///////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// task runSbg(type: BuildToolTask) { dependsOn "collectAllJars" - def rootPath = ""; + def rootPath = "" if (!findProject(':static-binding-generator').is(null)) { rootPath = Paths.get(project(':static-binding-generator').projectDir.path, "build/libs").toString() dependsOn ':static-binding-generator:jar' @@ -505,7 +490,7 @@ task runSbg(type: BuildToolTask) { mainClass = "-jar" def paramz = new ArrayList() - paramz.add(Paths.get(rootPath,"static-binding-generator.jar")) + paramz.add(Paths.get(rootPath, "static-binding-generator.jar")) if (failOnCompilationWarningsEnabled()) { paramz.add("-show-deprecation-warnings") @@ -551,7 +536,7 @@ def explodeAar(File compileDependency, File outputDir) { } } -def md5(String string) { +static def md5(String string) { MessageDigest digest = MessageDigest.getInstance("MD5") digest.update(string.bytes) return new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0') @@ -584,9 +569,9 @@ allprojects { def buildType = project.selectedBuildType def jars = [] def artifactType = Attribute.of('artifactType', String) - android.applicationVariants.all { variant -> + android.applicationVariants.configureEach { variant -> if (variant.buildType.name == buildType) { - variant.getCompileClasspath().each { fileDependency -> + variant.getCompileClasspath(null).each { fileDependency -> processJar(fileDependency, jars) } } @@ -604,7 +589,7 @@ def processJar(File jar, jars) { logger.debug("Creating dynamic task ${taskName}") // Add discovered jars as dependencies of cleanupAllJars. - // This is cruicial for cloud builds because they are different + // This is crucial for cloud builds because they are different // on each incremental build (as each time the gradle user home // directory is a randomly generated string) cleanupAllJars.inputs.files jar @@ -634,7 +619,7 @@ def processJar(File jar, jars) { } } -task cleanupAllJars { +task 'cleanupAllJars' { // We depend on the list of libs directories that might contain aar or jar files // and on the list of all discovered jars inputs.files(pluginDependencies) @@ -659,7 +644,7 @@ task cleanupAllJars { // Placeholder task which depends on all dynamically generated extraction tasks -task extractAllJars { +task 'extractAllJars' { dependsOn cleanupAllJars outputs.files extractAllJarsTimestamp @@ -668,7 +653,7 @@ task extractAllJars { } } -task collectAllJars { +task 'collectAllJars' { dependsOn extractAllJars description "gathers all paths to jar dependencies before building metadata with them" @@ -706,27 +691,31 @@ task collectAllJars { } } -task copyMetadataFilters(type: Copy) { - from "$rootDir/whitelist.mdg", "$rootDir/blacklist.mdg" - into "$BUILD_TOOLS_PATH" +task copyMetadataFilters { + outputs.files("$BUILD_TOOLS_PATH/whitelist.mdg", "$BUILD_TOOLS_PATH/blacklist.mdg") + // use an explicit copy task here because the copy task itselfs marks the whole built-tools as an output! + copy { + from file("$rootDir/whitelist.mdg"), file("$rootDir/blacklist.mdg") + into "$BUILD_TOOLS_PATH" + } } -task copyMetadata { +task 'copyMetadata' { doLast { copy { - from "$projectDir/src/main/assets/metadata" - into getMergedAssetsOutputPath() + "/metadata" + from "$projectDir/src/main/assets/metadata" + into getMergedAssetsOutputPath() + "/metadata" } } } def listf(String directoryName, ArrayList store) { - def directory = new File(directoryName); + def directory = new File(directoryName) - def resultList = new ArrayList(); + def resultList = new ArrayList() - def fList = directory.listFiles(); - resultList.addAll(Arrays.asList(fList)); + def fList = directory.listFiles() + resultList.addAll(Arrays.asList(fList)) for (File file : fList) { if (file.isFile()) { store.add(file) @@ -738,12 +727,173 @@ def listf(String directoryName, ArrayList store) { } task buildMetadata(type: BuildToolTask) { - def rootPath = ""; + def rootPath = "" if (!findProject(':android-metadata-generator').is(null)) { rootPath = Paths.get(project(':android-metadata-generator').projectDir.path, "build/libs").toString() dependsOn ':android-metadata-generator:jar' } + + + android.applicationVariants.all { variant -> + def buildTypeName = variant.buildType.name.capitalize() + def mergeShadersTaskName = "merge${buildTypeName}Shaders" + def mergeShadersTask = tasks.findByName(mergeShadersTaskName) + + if (mergeShadersTask) { + dependsOn mergeShadersTask + } + + def compileJavaWithJavacTaskName = "compile${buildTypeName}JavaWithJavac" + def compileJavaWithJavacTask = tasks.findByName(compileJavaWithJavacTaskName) + + + if (compileJavaWithJavacTask) { + dependsOn compileJavaWithJavacTask + } + + def compileKotlinTaskName = "compile${buildTypeName}Kotlin" + def compileKotlinTask = tasks.findByName(compileKotlinTaskName) + + + if (compileKotlinTask) { + dependsOn compileKotlinTask + } + + + def mergeDexTaskName = "mergeDex${buildTypeName}" + def mergeDexTask = tasks.findByName(mergeDexTaskName) + + if (mergeDexTask) { + dependsOn mergeDexTask + } + + def checkDuplicateClassesTaskName = "check${buildTypeName}DuplicateClasses" + def checkDuplicateClassesTask = tasks.findByName(checkDuplicateClassesTaskName) + + if (checkDuplicateClassesTask) { + dependsOn checkDuplicateClassesTask + } + + def generateBuildConfigTaskName = "generate${buildTypeName}BuildConfig" + def generateBuildConfigTask = tasks.findByName(generateBuildConfigTaskName) + + if (generateBuildConfigTask) { + dependsOn generateBuildConfigTask + } + + def dexBuilderTaskName = "dexBuilder${buildTypeName}" + def dexBuilderTask = tasks.findByName(dexBuilderTaskName) + + if (dexBuilderTask) { + dependsOn dexBuilderTask + } + + + def mergeExtDexTaskName = "mergeExtDex${buildTypeName}" + def mergeExtDexTask = tasks.findByName(mergeExtDexTaskName) + + if (mergeExtDexTask) { + dependsOn mergeExtDexTask + } + + def mergeLibDexTaskName = "mergeLibDex${buildTypeName}" + def mergeLibDexTask = tasks.findByName(mergeLibDexTaskName) + + if (mergeLibDexTask) { + dependsOn mergeLibDexTask + } + + def mergeProjectDexTaskName = "mergeProjectDex${buildTypeName}" + def mergeProjectDexTask = tasks.findByName(mergeProjectDexTaskName) + + if (mergeProjectDexTask) { + dependsOn mergeProjectDexTask + } + + def syncLibJarsTaskName = "sync${buildTypeName}LibJars" + def syncLibJarsTask = tasks.findByName(syncLibJarsTaskName) + + if (syncLibJarsTask) { + dependsOn syncLibJarsTask + } + + def mergeJavaResourceTaskName = "merge${buildTypeName}JavaResource" + def mergeJavaResourceTask = tasks.findByName(mergeJavaResourceTaskName) + + if (mergeJavaResourceTask) { + dependsOn mergeJavaResourceTask + } + + def mergeJniLibFoldersTaskName = "merge${buildTypeName}JniLibFolders" + def mergeJniLibFoldersTask = tasks.findByName(mergeJniLibFoldersTaskName) + + if (mergeJniLibFoldersTask) { + dependsOn mergeJniLibFoldersTask + } + + def mergeNativeLibsTaskName = "merge${buildTypeName}NativeLibs" + def mergeNativeLibsTask = tasks.findByName(mergeNativeLibsTaskName) + + if (mergeNativeLibsTask) { + dependsOn mergeNativeLibsTask + } + + def stripDebugSymbolsTaskName = "strip${buildTypeName}DebugSymbols" + def stripDebugSymbolsTask = tasks.findByName(stripDebugSymbolsTaskName) + + if (stripDebugSymbolsTask) { + dependsOn stripDebugSymbolsTask + } + + def validateSigningTaskName = "validateSigning${buildTypeName}" + def validateSigningTask = tasks.findByName(validateSigningTaskName) + + if (validateSigningTask) { + dependsOn validateSigningTask + } + + + def extractProguardFilesTaskName = "extractProguardFiles" + def extractProguardFilesTask = tasks.findByName(extractProguardFilesTaskName) + + if (extractProguardFilesTask) { + dependsOn extractProguardFilesTask + } + + + def compileArtProfileTaskName = "compile${buildTypeName}ArtProfile" + def compileArtProfileTask = tasks.findByName(compileArtProfileTaskName) + + if (compileArtProfileTask) { + dependsOn compileArtProfileTask + } + + + def extractNativeSymbolTablesTaskName = "extract${buildTypeName}NativeSymbolTables" + def extractNativeSymbolTablesTask = tasks.findByName(extractNativeSymbolTablesTaskName) + + if (extractNativeSymbolTablesTask) { + dependsOn extractNativeSymbolTablesTask + } + + + def optimizeResourcesTaskName = "optimize${buildTypeName}Resources" + def optimizeResourcesTask = tasks.findByName(optimizeResourcesTaskName) + + if (optimizeResourcesTask) { + dependsOn optimizeResourcesTask + } + + def bundleResourcesTaskName = "bundle${buildTypeName}Resources" + def bundleResourcesTask = tasks.findByName(bundleResourcesTaskName) + + if (bundleResourcesTask) { + dependsOn bundleResourcesTask + } + + } + dependsOn copyMetadataFilters // As some external gradle plugins can reorder the execution order of the tasks it may happen that buildMetadata is executed after merge{Debug/Release}Assets @@ -759,13 +909,17 @@ task buildMetadata(type: BuildToolTask) { inputs.files("$MDG_JAVA_DEPENDENCIES") // make MDG aware of whitelist.mdg and blacklist.mdg files - inputs.files(project.fileTree(dir: "$rootDir", include: "**/*.mdg")) + // inputs.files(project.fileTree(dir: "$rootDir", include: "**/*.mdg")) + // use explicit inputs as the above makes the whole build-tools directory an input! + inputs.files("$BUILD_TOOLS_PATH/whitelist.mdg", "$BUILD_TOOLS_PATH/blacklist.mdg") - def classesDir = "$buildDir/intermediates/javac" - inputs.dir(classesDir) + def classesDir = layout.buildDirectory.dir("intermediates/javac").get().asFile + if (classesDir.exists()) { + inputs.dir(classesDir) + } - def kotlinClassesDir = "$buildDir/tmp/kotlin-classes" - if (file(kotlinClassesDir).exists()) { + def kotlinClassesDir = layout.buildDirectory.dir("tmp/kotlin-classes").get().asFile + if (kotlinClassesDir.exists()) { inputs.dir(kotlinClassesDir) } @@ -785,8 +939,8 @@ task buildMetadata(type: BuildToolTask) { rootProject.subprojects { - def projectClassesDir = new File("$it.buildDir/intermediates/javac") - def projectKotlinClassesDir = new File("$it.buildDir/tmp/kotlin-classes") + def projectClassesDir = it.layout.buildDirectory.dir("intermediates/javac").get().asFile + def projectKotlinClassesDir = it.layout.buildDirectory.dir("tmp/kotlin-classes").get().asFile if (projectClassesDir.exists()) { def projectClassesSubDirs = projectClassesDir.listFiles() @@ -797,14 +951,14 @@ task buildMetadata(type: BuildToolTask) { } } - if (projectKotlinClassesDir.exists()) { - def projectKotlinClassesSubDirs = projectKotlinClassesDir.listFiles(); - for (File subDir : projectKotlinClassesSubDirs) { - if (!kotlinClassesSubDirs.contains(subDir)) { - kotlinClassesSubDirs.add(subDir) - } + if (projectKotlinClassesDir.exists()) { + def projectKotlinClassesSubDirs = projectKotlinClassesDir.listFiles() + for (File subDir : projectKotlinClassesSubDirs) { + if (!kotlinClassesSubDirs.contains(subDir)) { + kotlinClassesSubDirs.add(subDir) + } + } } - } } def generatedClasses = new LinkedList() @@ -821,7 +975,7 @@ task buildMetadata(type: BuildToolTask) { } def store = new ArrayList() - for (String dir: generatedClasses){ + for (String dir : generatedClasses) { listf(dir, store) } @@ -846,11 +1000,11 @@ task buildMetadata(type: BuildToolTask) { def paramz = new ArrayList() paramz.add(Paths.get(rootPath, "android-metadata-generator.jar")) - if(enableAnalytics){ + if (enableAnalytics) { paramz.add("analyticsFilePath=$analyticsFilePath") } - if(enableVerboseMDG){ + if (enableVerboseMDG) { paramz.add("verbose") } @@ -912,7 +1066,7 @@ static def shouldIncludeDirForTypings(path, includeDirs) { return false } -task copyTypings { +task 'copyTypings' { doLast { outLogger.withStyle(Style.Info).println "Copied generated typings to application root level. Make sure to import android.d.ts in reference.d.ts" @@ -926,12 +1080,12 @@ task copyTypings { copyTypings.onlyIf { generateTypescriptDefinitions.didWork } generateTypescriptDefinitions.finalizedBy(copyTypings) -task validateAppIdMatch { +task 'validateAppIdMatch' { doLast { def lineSeparator = System.getProperty("line.separator") if (project.hasProperty("nsApplicationIdentifier") && !project.hasProperty("release")) { - if (project.nsApplicationIdentifier != android.defaultConfig.applicationId) { + if (project.nsApplicationIdentifier != android.defaultConfig.applicationId && android.namespace != appIdentifier) { def errorMessage = "${lineSeparator}WARNING: The Application identifier is different from the one inside \"package.json\" file.$lineSeparator" + "NativeScript CLI might not work properly.$lineSeparator" + "Remove applicationId from app.gradle and update the \"nativescript.id\" in package.json.$lineSeparator" + @@ -970,3 +1124,186 @@ task cleanMdg(type: Delete) { cleanSbg.dependsOn(cleanMdg) clean.dependsOn(cleanSbg) + + +//dependsOn { +// pattern { +// include "merge*.Shaders" // Matches tasks starting with "merge" and ending with "Shaders" +// } +//} + + +tasks.configureEach({ DefaultTask currentTask -> + // println "\t ~ [DEBUG][app] build.gradle - currentTask = ${currentTask.name} ..." + + if (currentTask =~ /compile.+JavaWithJavac/) { + currentTask.dependsOn(runSbg) + } + + if (currentTask =~ /mergeDex.+/) { + currentTask.dependsOn(runSbg) + } + + if (currentTask =~ /compile.+Kotlin.+/) { + currentTask.dependsOn(runSbg) + } + + if (currentTask =~ /merge.*Assets/) { + currentTask.dependsOn(buildMetadata) + } + +// // ensure buildMetadata is done before R8 to allow custom proguard from metadata + if (currentTask =~ /minify.*WithR8/) { + buildMetadata.finalizedBy(currentTask) + } + if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) { + currentTask.finalizedBy("validateAppIdMatch") + } + + if (currentTask =~ /process.+Resources/) { + cleanupAllJars.dependsOn(currentTask) + } + +// if (currentTask.name == "extractProguardFiles") { +// currentTask.finalizedBy(buildMetadata) +// } +// + if (currentTask =~ /generate.+LintVitalReportModel/) { + currentTask.dependsOn(buildMetadata) + } + + if (currentTask =~ /lintVitalAnalyze.+/) { + currentTask.dependsOn(buildMetadata) + } +// +// if (currentTask =~ /merge.+GlobalSynthetics/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /optimize.+Resources/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /buildCMake.*/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /configureCMake.*/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /validateSigning.*/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /generate.*LintReportModel/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /generate.*AndroidTestResValues/) { +// // buildMetadata.dependsOn(currentTask) +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /generate.*AndroidTestLintModel/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /generate.*UnitTestLintModel/) { +// buildMetadata.mustRunAfter(currentTask) +// } +// +// if (currentTask =~ /generate.*UnitTestLintModel/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// +// if (currentTask =~ /lintAnalyze.*UnitTest/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /process.*JavaRes/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /strip.*DebugSymbols/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /merge.*JavaResource/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /lintAnalyze.*/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /lintAnalyze.*AndroidTest/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /bundle.*Resources/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /compile.*ArtProfile/) { +// currentTask.mustRunAfter(buildMetadata) +// } +// +// if (currentTask =~ /check.*DuplicateClasses/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /check.*AarMetadata/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /create.*CompatibleScreenManifests/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /process.*Manifest/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /generate.*ResValues/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /merge.*Resources/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /package.*Resources/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /process.*Resources/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /desugar.*Dependencies/) { +// currentTask.finalizedBy(buildMetadata) +// } +// +// if (currentTask =~ /merge.*JniLibFolders/) { +// currentTask.finalizedBy(buildMetadata) +// } + +}) + +rootProject.subprojects.forEach { + it.tasks.configureEach({ DefaultTask currentTask -> + if (currentTask =~ /.+bundleLibCompileToJar.*/) { + currentTask.finalizedBy(cleanupAllJars) + } + + if (currentTask =~ /bundleLibRuntimeToDir.*/) { + currentTask.finalizedBy(buildMetadata) + } + + if (currentTask =~ /compile.*LibraryResources/) { + currentTask.finalizedBy(buildMetadata) + } + }) +} diff --git a/test-app/app/src/main/AndroidManifest.xml b/test-app/app/src/main/AndroidManifest.xml index dee1642b6..b0a7d50b3 100644 --- a/test-app/app/src/main/AndroidManifest.xml +++ b/test-app/app/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ - + - + = Integer.toUnsignedLong(array_offset)) { + throw new Exception("Non-array metadata has overflown array space. Please report this issue."); + } + d.addAll(n.children); } @@ -326,7 +343,7 @@ public void writeTree(TreeNode root) throws Exception { TreeNode n = d.pollFirst(); if (n.arrayElement != null) { - n.offsetValue = array_offset + n.arrayElement.id; + n.offsetValue = array_offset + Short.toUnsignedInt(n.arrayElement.id); } if (!n.children.isEmpty()) { @@ -351,7 +368,7 @@ public void writeTree(TreeNode root) throws Exception { while (!d.isEmpty()) { TreeNode n = d.pollFirst(); - nodeData[0] = n.firstChildId + (n.nextSiblingId << 16); + nodeData[0] = (n.firstChildId & 0xFFFF) | (n.nextSiblingId << 16); nodeData[1] = n.offsetName; nodeData[2] = n.offsetValue; @@ -364,5 +381,26 @@ public void writeTree(TreeNode root) throws Exception { outNodeStream.flush(); outNodeStream.close(); + + if (outDebugStream != null) { + d.push(root); + JsonArray rootArray = new JsonArray(); + while (!d.isEmpty()) { + TreeNode n = d.pollFirst(); + JsonObject obj = new JsonObject(); + obj.addProperty("id", Short.toUnsignedInt(n.id)); + obj.addProperty("nextSiblingId", Short.toUnsignedInt(n.nextSiblingId)); + obj.addProperty("firstChildId", Short.toUnsignedInt(n.firstChildId)); + obj.addProperty("offsetName", Integer.toUnsignedLong(n.offsetName)); + obj.addProperty("offsetValue", Integer.toUnsignedLong(n.offsetValue)); + obj.addProperty("name", n.getName()); + obj.addProperty("nodeType", n.nodeType); + rootArray.add(obj); + d.addAll(n.children); + } + outDebugStream.write(rootArray.toString().getBytes()); + outDebugStream.flush(); + outDebugStream.close(); + } } } diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/classes/KotlinClassDescriptor.kt b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/classes/KotlinClassDescriptor.kt index bc3f8c5e6..43e6bf272 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/classes/KotlinClassDescriptor.kt +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/classes/KotlinClassDescriptor.kt @@ -15,13 +15,14 @@ import com.telerik.metadata.parsing.kotlin.metadata.bytecode.BytecodeClassMetada import com.telerik.metadata.parsing.kotlin.methods.KotlinMethodDescriptor import com.telerik.metadata.parsing.kotlin.properties.KotlinPropertyDescriptor import com.telerik.metadata.security.classes.SecuredClassRepository -import kotlinx.metadata.Flag -import kotlinx.metadata.KmClass -import kotlinx.metadata.KmProperty -import kotlinx.metadata.jvm.KotlinClassMetadata -import kotlinx.metadata.jvm.Metadata -import kotlinx.metadata.jvm.getterSignature -import kotlinx.metadata.jvm.setterSignature +import kotlin.metadata.KmClass +import kotlin.metadata.KmProperty +import kotlin.metadata.Visibility +import kotlin.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.jvm.Metadata +import kotlin.metadata.jvm.getterSignature +import kotlin.metadata.jvm.setterSignature +import kotlin.metadata.visibility import org.apache.bcel.classfile.JavaClass import java.io.IOException import java.nio.file.Files @@ -48,7 +49,7 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati var kotlinMetadataProperties: Collection = emptyList() if (meta is KotlinClassMetadata.Class) { - val metaClass = meta.toKmClass() + val metaClass = meta.kmClass kotlinMetadataProperties = metaClass.properties val possibleCompanionField = getCompanionFieldIfAny(nativeClass, metaClass) @@ -68,9 +69,9 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati } } else if (meta is KotlinClassMetadata.FileFacade) { - kotlinMetadataProperties = meta.toKmPackage().properties + kotlinMetadataProperties = meta.kmPackage.properties } else if (meta is KotlinClassMetadata.MultiFileClassPart) { - kotlinMetadataProperties = meta.toKmPackage().properties + kotlinMetadataProperties = meta.kmPackage.properties } @@ -95,11 +96,11 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati if (field.name == prop.name) { val kotlinField = KotlinJvmFieldDescriptor( field = field, - isPublic = Flag.IS_PUBLIC(prop.flags), - isInternal = Flag.IS_INTERNAL(prop.flags), - isProtected = Flag.IS_PROTECTED(prop.flags), + isPublic = prop.visibility == Visibility.PUBLIC, + isInternal = prop.visibility == Visibility.INTERNAL, + isProtected = prop.visibility == Visibility.PROTECTED, isPackagePrivate, - isPrivate = Flag.IS_PRIVATE(prop.flags), + isPrivate = prop.visibility == Visibility.PRIVATE, ) kotlinFields.add(kotlinField) @@ -191,13 +192,17 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati var getter: NativeMethodDescriptor? = null val getterSignature = it.getterSignature if (getterSignature != null) { - getter = getMethodDescriptorWithSignature(getterSignature.name, getterSignature.desc) + getter = getMethodDescriptorWithSignature(getterSignature.name, + getterSignature.descriptor + ) } var setter: NativeMethodDescriptor? = null val setterSignature = it.setterSignature if (setterSignature != null) { - setter = getMethodDescriptorWithSignature(setterSignature.name, setterSignature.desc) + setter = getMethodDescriptorWithSignature(setterSignature.name, + setterSignature.descriptor + ) } KotlinPropertyDescriptor(propertyName, getter, setter, duplicate) @@ -225,28 +230,28 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati override val isPublic by lazy { when (val metadata = kotlinMetadata) { - is KotlinClassMetadata.Class -> Flag.IS_PUBLIC(metadata.toKmClass().flags) + is KotlinClassMetadata.Class -> metadata.kmClass.visibility == Visibility.PUBLIC else -> clazz.isPublic } } override val isInternal by lazy { when (val metadata = kotlinMetadata) { - is KotlinClassMetadata.Class -> Flag.IS_INTERNAL(metadata.toKmClass().flags) + is KotlinClassMetadata.Class -> metadata.kmClass.visibility == Visibility.INTERNAL else -> false } } override val isProtected by lazy { when (val metadata = kotlinMetadata) { - is KotlinClassMetadata.Class -> Flag.IS_PROTECTED(metadata.toKmClass().flags) + is KotlinClassMetadata.Class -> metadata.kmClass.visibility == Visibility.PROTECTED else -> clazz.isProtected } } override val isPrivate by lazy { when (val metadata = kotlinMetadata) { - is KotlinClassMetadata.Class -> Flag.IS_PRIVATE(metadata.toKmClass().flags) + is KotlinClassMetadata.Class -> metadata.kmClass.visibility == Visibility.PRIVATE else -> clazz.isPrivate } } @@ -262,7 +267,7 @@ class KotlinClassDescriptor(nativeClass: JavaClass, private val metadataAnnotati metadataAnnotation.packageName, metadataAnnotation.extraInt) - KotlinClassMetadata.read(metadata) + KotlinClassMetadata.readStrict(metadata) } diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/extensions/bytecode/BytecodeExtensionFunctionsCollector.kt b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/extensions/bytecode/BytecodeExtensionFunctionsCollector.kt index cf3e985ed..86a2fb91d 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/extensions/bytecode/BytecodeExtensionFunctionsCollector.kt +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/extensions/bytecode/BytecodeExtensionFunctionsCollector.kt @@ -7,7 +7,7 @@ import com.telerik.metadata.parsing.kotlin.extensions.KotlinExtensionFunctionDes import com.telerik.metadata.parsing.kotlin.extensions.ExtensionFunctionsCollector import com.telerik.metadata.parsing.kotlin.metadata.ClassMetadataParser import com.telerik.metadata.parsing.kotlin.methods.KotlinMethodDescriptor -import kotlinx.metadata.jvm.signature +import kotlin.metadata.jvm.signature import java.util.* class BytecodeExtensionFunctionsCollector(private val kotlinClassMetadataParser: ClassMetadataParser) : ExtensionFunctionsCollector { @@ -24,7 +24,7 @@ class BytecodeExtensionFunctionsCollector(private val kotlinClassMetadataParser: if (signature != null) { val functionName = signature.name - val functionSignature = signature.desc + val functionSignature = signature.descriptor val extensionFunctionDescriptor: KotlinMethodDescriptor = Arrays .stream(kotlinClassDescriptor.methods) diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/ClassMetadataParser.kt b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/ClassMetadataParser.kt index 732a3f63c..e99bb32b3 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/ClassMetadataParser.kt +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/ClassMetadataParser.kt @@ -2,9 +2,9 @@ package com.telerik.metadata.parsing.kotlin.metadata import com.telerik.metadata.parsing.NativeClassDescriptor -import kotlinx.metadata.KmFunction -import kotlinx.metadata.KmProperty -import kotlinx.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.KmFunction +import kotlin.metadata.KmProperty +import kotlin.metadata.jvm.KotlinClassMetadata import java.util.stream.Stream interface ClassMetadataParser { diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/bytecode/BytecodeClassMetadataParser.kt b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/bytecode/BytecodeClassMetadataParser.kt index 28b2a2110..53f81b69c 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/bytecode/BytecodeClassMetadataParser.kt +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/metadata/bytecode/BytecodeClassMetadataParser.kt @@ -3,10 +3,11 @@ package com.telerik.metadata.parsing.kotlin.metadata.bytecode import com.telerik.metadata.parsing.NativeClassDescriptor import com.telerik.metadata.parsing.kotlin.classes.KotlinClassDescriptor import com.telerik.metadata.parsing.kotlin.metadata.ClassMetadataParser -import kotlinx.metadata.Flag -import kotlinx.metadata.KmFunction -import kotlinx.metadata.KmProperty -import kotlinx.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.KmFunction +import kotlin.metadata.KmProperty +import kotlin.metadata.Visibility +import kotlin.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.visibility import java.lang.reflect.Modifier import java.util.stream.Stream @@ -19,7 +20,7 @@ class BytecodeClassMetadataParser : ClassMetadataParser { val kotlinMetadata = clazz.kotlinMetadata if (kotlinMetadata is KotlinClassMetadata.Class) { - val kmClass = kotlinMetadata.toKmClass() + val kmClass = kotlinMetadata.kmClass kmClass.companionObject val companion = kmClass.companionObject val fullCompanionName = clazz.className + "$" + companion @@ -31,15 +32,15 @@ class BytecodeClassMetadataParser : ClassMetadataParser { override fun getKotlinProperties(kotlinMetadata: KotlinClassMetadata): Stream { if (kotlinMetadata is KotlinClassMetadata.Class) { - val kmClass = kotlinMetadata.toKmClass() + val kmClass = kotlinMetadata.kmClass return kmClass.properties .stream() .filter { - Flag.IS_PUBLIC(it.flags) || Flag.IS_PROTECTED(it.flags) + it.visibility == Visibility.PUBLIC || it.visibility == Visibility.PROTECTED } .filter { p -> - ((Modifier.isPublic(p.getterFlags) || Modifier.isProtected(p.getterFlags)) - && (Modifier.isPublic(p.setterFlags) || Modifier.isProtected(p.setterFlags)) + ((p.getter.visibility == Visibility.PUBLIC || p.getter.visibility == Visibility.PROTECTED) + && (p.setter?.visibility == Visibility.PUBLIC || p.setter?.visibility == Visibility.PROTECTED) && !p.name.startsWith("is")) } } @@ -49,13 +50,13 @@ class BytecodeClassMetadataParser : ClassMetadataParser { override fun getKotlinExtensionFunctions(kotlinMetadata: KotlinClassMetadata): Stream { if (kotlinMetadata is KotlinClassMetadata.Class) { - val kmClass = kotlinMetadata.toKmClass() + val kmClass = kotlinMetadata.kmClass return kmClass.functions .stream() .filter { isVisibleExtensionFunction(it) } } else if (kotlinMetadata is KotlinClassMetadata.FileFacade) { - val kmClass = kotlinMetadata.toKmPackage() + val kmClass = kotlinMetadata.kmPackage return kmClass.functions .stream() diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/methods/KotlinMethodDescriptor.kt b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/methods/KotlinMethodDescriptor.kt index 89fc10cca..9ec1a640c 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/methods/KotlinMethodDescriptor.kt +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/parsing/kotlin/methods/KotlinMethodDescriptor.kt @@ -2,10 +2,11 @@ package com.telerik.metadata.parsing.kotlin.methods import com.telerik.metadata.parsing.bytecode.methods.NativeMethodBytecodeDescriptor import com.telerik.metadata.parsing.kotlin.classes.KotlinClassDescriptor -import kotlinx.metadata.Flag -import kotlinx.metadata.KmDeclarationContainer -import kotlinx.metadata.jvm.KotlinClassMetadata -import kotlinx.metadata.jvm.signature +import kotlin.metadata.KmDeclarationContainer +import kotlin.metadata.Visibility +import kotlin.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.jvm.signature +import kotlin.metadata.visibility import org.apache.bcel.classfile.Method class KotlinMethodDescriptor(private val method: Method, private val originClass: KotlinClassDescriptor, @@ -26,11 +27,15 @@ class KotlinMethodDescriptor(private val method: Method, private val originClass override val isInternal by lazy { return@lazy when (val kotlinMetadata = originClass.kotlinMetadata) { - is KotlinClassMetadata.Class -> checkIfMethodIsInternal(method, kotlinMetadata.toKmClass()) - is KotlinClassMetadata.FileFacade -> checkIfMethodIsInternal(method, kotlinMetadata.toKmPackage()) + is KotlinClassMetadata.Class -> checkIfMethodIsInternal(method, kotlinMetadata.kmClass) + is KotlinClassMetadata.FileFacade -> checkIfMethodIsInternal(method, + kotlinMetadata.kmPackage + ) is KotlinClassMetadata.SyntheticClass -> false is KotlinClassMetadata.MultiFileClassFacade -> false - is KotlinClassMetadata.MultiFileClassPart -> checkIfMethodIsInternal(method, kotlinMetadata.toKmPackage()) + is KotlinClassMetadata.MultiFileClassPart -> checkIfMethodIsInternal(method, + kotlinMetadata.kmPackage + ) is KotlinClassMetadata.Unknown -> false null -> false } @@ -40,8 +45,8 @@ class KotlinMethodDescriptor(private val method: Method, private val originClass val function = kotlinDeclarationContainer .functions .firstOrNull { - it.signature != null && it.signature!!.name == method.name && it.signature!!.desc == method.signature + it.signature != null && it.signature!!.name == method.name && it.signature!!.descriptor == method.signature } - return if (function != null) Flag.IS_INTERNAL(function.flags) else false + return if (function != null) function.visibility == Visibility.INTERNAL else false } } \ No newline at end of file diff --git a/test-app/build-tools/static-binding-generator/build.gradle b/test-app/build-tools/static-binding-generator/build.gradle index 0fe6445ae..42fd71f04 100644 --- a/test-app/build-tools/static-binding-generator/build.gradle +++ b/test-app/build-tools/static-binding-generator/build.gradle @@ -1,8 +1,5 @@ apply plugin: 'java-library' -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - // todo: check if still needed // if(!project.hasProperty("loadedProjectDeps")){ // Properties projectDeps = new Properties() @@ -34,32 +31,62 @@ dependencies { compileJava { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } -jar { +configurations.create("staticBindingGeneratorTestImplementation") { + extendsFrom configurations.testImplementation + setCanBeResolved(true) +} + +configurations.create("staticBindingGeneratorImplementation") { + extendsFrom configurations.implementation + setCanBeResolved(true) +} + +configurations.create("staticBindingGeneratorRuntimeOnly") { + extendsFrom configurations.runtimeOnly + setCanBeResolved(true) +} + +configurations.create("staticBindingGeneratorApi") { + extendsFrom configurations.api + setCanBeResolved(true) +} - configurations.implementation.setCanBeResolved(true) - configurations.runtimeOnly.setCanBeResolved(true) - configurations.api.setCanBeResolved(true) +jar { manifest { - attributes("Manifest-Version": "1.0", + attributes("Manifest-Version": "2.0", "Main-Class": "org.nativescript.staticbindinggenerator.Main") } from { - configurations.implementation.collect { + configurations.staticBindingGeneratorTestImplementation.collect { + it.isDirectory() ? it : zipTree(it) + } + + configurations.staticBindingGeneratorImplementation.collect { it.isDirectory() ? it : zipTree(it) } - configurations.runtimeOnly.collect { + configurations.staticBindingGeneratorRuntimeOnly.collect { it.isDirectory() ? it : zipTree(it) } - configurations.api.collect { + configurations.staticBindingGeneratorApi.collect { it.isDirectory() ? it : zipTree(it) } } duplicatesStrategy = 'include' } + +def copyMetadataFilters = tasks.findByPath(":app:copyMetadataFilters") +if (copyMetadataFilters != null) { + compileJava.dependsOn(copyMetadataFilters) + if (processTestResources) { + processTestResources.dependsOn(copyMetadataFilters) + } +} diff --git a/test-app/build-tools/static-binding-generator/runtests.gradle b/test-app/build-tools/static-binding-generator/runtests.gradle index cd7e770a8..321ae9f68 100644 --- a/test-app/build-tools/static-binding-generator/runtests.gradle +++ b/test-app/build-tools/static-binding-generator/runtests.gradle @@ -44,14 +44,20 @@ def outputFile = file('../sbg-output-file.txt') def javaDependenciesFile = file('../sbg-java-dependencies.txt') def interfaceNamesFile = file('../sbg-interface-names.txt') + +configurations.create("runTestsApi") { + extendsFrom configurations.api + setCanBeResolved(true) +} + + jar { - configurations.api.setCanBeResolved(true) manifest { attributes("Manifest-Version": "1.0", "Main-Class": "org.nativescript.staticbindinggenerator.Main") } from { - configurations.api.collect { + configurations.runTestsApi.collect { it.isDirectory() ? it : zipTree(it) } } @@ -73,6 +79,6 @@ task runSbg(type: JavaExec, dependsOn: 'prepareInputFiles') { main = "org.nativescript.staticbindinggenerator.Main" } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } \ No newline at end of file diff --git a/test-app/build.gradle b/test-app/build.gradle index 55ca4c66d..99a1643b2 100644 --- a/test-app/build.gradle +++ b/test-app/build.gradle @@ -38,9 +38,9 @@ version of the {N} CLI install a previous version of the runtime package - 'tns """) } - project.ext.extractedDependenciesDir = "${project.buildDir}/exploded-dependencies" - project.ext.cleanupAllJarsTimestamp = "${project.buildDir}/cleanupAllJars.timestamp" - project.ext.extractAllJarsTimestamp = "${project.buildDir}/extractAllJars.timestamp" + project.ext.extractedDependenciesDir = "${project.layout.buildDirectory.dir("exploded-dependencies").get().asFile}" + project.ext.cleanupAllJarsTimestamp = "${project.layout.buildDirectory.file("cleanupAllJars.timestamp").get().asFile}" + project.ext.extractAllJarsTimestamp = "${project.layout.buildDirectory.file("extractAllJars.timestamp").get().asFile}" project.ext.nativescriptDependencies = new JsonSlurper().parseText(dependenciesJson.text) @@ -144,7 +144,7 @@ version of the {N} CLI install a previous version of the runtime package - 'tns dependencies { classpath "com.android.tools.build:gradle:$androidBuildToolsVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - classpath "org.codehaus.groovy:groovy-all:3.0.8" + classpath "org.apache.groovy:groovy-all:4.0.21" } } @@ -165,6 +165,6 @@ allprojects { } } -task clean(type: Delete) { - delete rootProject.buildDir -} +task clean (type:Delete) { + delete rootProject.layout.buildDirectory.get().asFile +} \ No newline at end of file diff --git a/test-app/gradle.properties b/test-app/gradle.properties index d78e7d3ca..5751b4e48 100644 --- a/test-app/gradle.properties +++ b/test-app/gradle.properties @@ -19,27 +19,27 @@ android.enableJetifier=true android.useAndroidX=true # Default versions used throughout the gradle configurations -NS_DEFAULT_BUILD_TOOLS_VERSION=33.0.0 -NS_DEFAULT_COMPILE_SDK_VERSION=33 -NS_DEFAULT_MIN_SDK_VERSION=17 -NS_DEFAULT_ANDROID_BUILD_TOOLS_VERSION=7.4.2 +NS_DEFAULT_BUILD_TOOLS_VERSION=35.0.0 +NS_DEFAULT_COMPILE_SDK_VERSION=35 +NS_DEFAULT_MIN_SDK_VERSION=21 +NS_DEFAULT_ANDROID_BUILD_TOOLS_VERSION=8.7.0 -ns_default_androidx_appcompat_version = 1.5.1 -ns_default_androidx_exifinterface_version = 1.3.3 -ns_default_androidx_fragment_version = 1.5.3 -ns_default_androidx_material_version = 1.6.1 +ns_default_androidx_appcompat_version = 1.7.0 +ns_default_androidx_exifinterface_version = 1.3.7 +ns_default_androidx_fragment_version = 1.8.5 +ns_default_androidx_material_version = 1.8.0 ns_default_androidx_multidex_version = 2.0.1 -ns_default_androidx_transition_version = 1.4.1 +ns_default_androidx_transition_version = 1.5.1 ns_default_androidx_viewpager_version = 1.0.0 -ns_default_asm_util_version = 7.0 -ns_default_asm_version = 7.0 -ns_default_bcel_version = 6.5.0 +ns_default_asm_util_version = 9.7 +ns_default_asm_version = 9.7 +ns_default_bcel_version = 6.8.2 ns_default_commons_io_version = 2.6 ns_default_google_java_format_version = 1.6 -ns_default_gson_version = 2.9.0 +ns_default_gson_version = 2.10.1 ns_default_json_version = 20180813 ns_default_junit_version = 4.13.2 -ns_default_kotlin_version = 1.7.10 -ns_default_kotlinx_metadata_jvm_version = 0.6.2 +ns_default_kotlin_version = 2.0.0 +ns_default_kotlinx_metadata_jvm_version = 2.0.0 ns_default_mockito_core_version = 3.0.0 ns_default_spotbugs_version = 3.1.12 diff --git a/test-app/gradle/wrapper/gradle-wrapper.properties b/test-app/gradle/wrapper/gradle-wrapper.properties index 070cb702f..00fe486f0 100644 --- a/test-app/gradle/wrapper/gradle-wrapper.properties +++ b/test-app/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Tue Feb 11 10:56:28 AST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/test-app/package.json b/test-app/package.json index 7ec7b1851..ada9f8e81 100644 --- a/test-app/package.json +++ b/test-app/package.json @@ -4,8 +4,8 @@ "version": "1.0.0", "private": true, "dependencies": { - "@nativescript/core": "~8.4.0", - "nativescript": "~8.4.0" + "@nativescript/core": "~8.7.0", + "nativescript": "~8.7.0" }, "devDependencies": {} } diff --git a/test-app/runtime-binding-generator/build.gradle b/test-app/runtime-binding-generator/build.gradle index c158377b4..d7f20b314 100644 --- a/test-app/runtime-binding-generator/build.gradle +++ b/test-app/runtime-binding-generator/build.gradle @@ -6,8 +6,10 @@ dependencies { testImplementation "junit:junit:${ns_default_junit_version}" } -sourceCompatibility = JavaVersion.VERSION_1_7 -targetCompatibility = JavaVersion.VERSION_1_7 +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} // Disable compilation tasks as these are compiled *with* the runtime and not separately compileJava.enabled = false diff --git a/test-app/runtime/CMakeLists.txt b/test-app/runtime/CMakeLists.txt index 60b0a1714..8ff8a68af 100644 --- a/test-app/runtime/CMakeLists.txt +++ b/test-app/runtime/CMakeLists.txt @@ -1,7 +1,7 @@ # documentation: https://d.android.com/studio/projects/add-native-code.html # Command info: https://cmake.org/cmake/help/v3.4/command/cmake_minimum_required.html -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.18.1) project(NativeScriptAndroidRuntime) @@ -18,13 +18,16 @@ endif (CCACHE_FOUND AND (USE_CCACHE)) # "-DANDROID_STL=c++_static" is just not enough for clang++ to find some libraries in the ndk MESSAGE(STATUS "## ANDROID_NDK_ROOT: " ${ANDROID_NDK_ROOT}) -set(COMMON_CMAKE_ARGUMENTS "-std=c++17 -Werror -Wno-unused-result -mstackrealign -fexceptions -fno-builtin-stpcpy -fno-rtti -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -DV8_EMBEDDED_BUILTINS") + +set(COMMON_CMAKE_ARGUMENTS "-std=c++20 -Werror -Wno-unused-result -mstackrealign -fexceptions -fno-builtin-stpcpy -fno-rtti -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -DV8_EMBEDDED_BUILTINS -Wno-vla-extension -Wno-deprecated -Wno-vla-cxx-extension") + if("${ANDROID_ABI}" MATCHES "arm64-v8a$" OR "${ANDROID_ABI}" MATCHES "x86_64$") # Enable pointer compression on 64 bit platforms set(COMMON_CMAKE_ARGUMENTS "${COMMON_CMAKE_ARGUMENTS} -DV8_COMPRESS_POINTERS") endif() + # AOSP has switched to using LLD by default and the NDK will use it by default in the next release. # BFD and Gold will be removed once LLD has been through a release cycle with no major unresolved issues (estimated r21) # Note: lld does not currently work on Windows: https://github.com/android-ndk/ndk/issues/888 @@ -52,6 +55,7 @@ include_directories( src/main/cpp src/main/cpp/include src/main/cpp/v8_inspector + src/main/cpp/ada ) if (OPTIMIZED_BUILD OR OPTIMIZED_WITH_INSPECTOR_BUILD) @@ -69,9 +73,9 @@ if (NOT OPTIMIZED_BUILD OR OPTIMIZED_WITH_INSPECTOR_BUILD) INSPECTOR_SOURCES src/main/cpp/com_tns_AndroidJsV8Inspector.cpp - src/main/cpp/DOMDomainCallbackHandlers.cpp src/main/cpp/JsV8InspectorClient.cpp - src/main/cpp/NetworkDomainCallbackHandlers.cpp + src/main/cpp/v8_inspector/ns-v8-tracing-agent-impl.cpp + src/main/cpp/v8_inspector/Utils.cpp ) else () # When building in Release mode we do not include the V8 inspector sources @@ -114,7 +118,9 @@ add_library( src/main/cpp/MetadataNode.cpp src/main/cpp/MetadataReader.cpp src/main/cpp/MetadataTreeNode.cpp + src/main/cpp/MetadataEntry.cpp src/main/cpp/MethodCache.cpp + src/main/cpp/ModuleBinding.cpp src/main/cpp/ModuleInternal.cpp src/main/cpp/NativeScriptException.cpp src/main/cpp/NumericCasts.cpp @@ -136,6 +142,10 @@ add_library( src/main/cpp/conversions/objects/JSToJavaObjectsConverter.cpp src/main/cpp/conversions/arrays/JSToJavaArraysConverter.cpp src/main/cpp/conversions/primitives/JSToJavaPrimitivesConverter.cpp + src/main/cpp/ada/ada.cpp + src/main/cpp/URLImpl.cpp + src/main/cpp/URLSearchParamsImpl.cpp + src/main/cpp/URLPatternImpl.cpp # V8 inspector source files will be included only in Release mode ${INSPECTOR_SOURCES} @@ -157,6 +167,7 @@ else () ) endif () + MESSAGE(STATUS "# General cmake Info") MESSAGE(STATUS "# PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR}) MESSAGE(STATUS "# CMAKE_VERSION: " ${CMAKE_VERSION}) @@ -170,12 +181,6 @@ MESSAGE(STATUS "# CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS}) target_link_libraries(NativeScript ${PROJECT_SOURCE_DIR}/src/main/libs/${ANDROID_ABI}/libzip.a) target_link_libraries(NativeScript ${PROJECT_SOURCE_DIR}/src/main/libs/${ANDROID_ABI}/libv8_monolith.a) -if("${ANDROID_ABI}" MATCHES "armeabi-v7a$" OR "${ANDROID_ABI}" MATCHES "x86$") - # On API Level 19 and lower we need to link with android_support - # because it contains some implementation of functions such as "strtoll" and "strtoul" - MESSAGE(STATUS "# Linking with libandroid_support.a") - target_link_libraries(NativeScript ${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libandroid_support.a) -endif() # Command info: https://cmake.org/cmake/help/v3.4/command/find_library.html # Searches for a specified prebuilt library and stores the path as a diff --git a/test-app/runtime/build.gradle b/test-app/runtime/build.gradle index e92b16055..723300f73 100644 --- a/test-app/runtime/build.gradle +++ b/test-app/runtime/build.gradle @@ -21,6 +21,7 @@ if (useCCache) { } +def defaultNdkVersion = "27.2.12479018" def hasNdkVersion = project.hasProperty("ndkVersion") if (hasNdkVersion) { @@ -30,29 +31,50 @@ if (hasNdkVersion) { def NDK_PATH = "" def hasNdkDirectory = project.hasProperty("ndkDirectory") -if(!hasNdkDirectory){ +if (!hasNdkDirectory) { println "No ndkDirectory set, checking environment \$ANDROID_NDK..." - + NDK_PATH = "$System.env.ANDROID_NDK" - if (NDK_PATH == null || NDK_PATH == "null"){ + if (NDK_PATH == null || NDK_PATH == "null") { println "No ndkDirectory set, checking environment \$ANDROID_NDK_ROOT..." NDK_PATH = "$System.env.ANDROID_NDK_ROOT" } - - if (NDK_PATH == null || NDK_PATH == "null"){ + + if (NDK_PATH == null || NDK_PATH == "null") { println "No ndkDirectory set, checking environment \$ANDROID_NDK_HOME..." NDK_PATH = "$System.env.ANDROID_NDK_HOME" } } else { NDK_PATH = ndkDirectory } + +if (NDK_PATH == null || NDK_PATH == "null" || NDK_PATH == "") { + if (!hasNdkVersion) { + NDK_PATH = "$System.env.ANDROID_HOME/ndk/${defaultNdkVersion}" + } else { + NDK_PATH = "$System.env.ANDROID_HOME/ndk/${ndkVersion}" + } +} + println "Runtime using NDK_PATH: " + NDK_PATH +base { + if (!optimized && !optimizedWithInspector) { + archivesName = "${base.archivesName.get()}-regular" + } else { + if (optimized) { + archivesName = "${base.archivesName.get()}-optimized" + } else if (optimizedWithInspector) { + archivesName = "${base.archivesName.get()}-optimized-with-inspector" + } + } +} + android { namespace "com.tns.android_runtime" - compileSdkVersion NS_DEFAULT_COMPILE_SDK_VERSION as int - buildToolsVersion NS_DEFAULT_BUILD_TOOLS_VERSION as String + compileSdk NS_DEFAULT_COMPILE_SDK_VERSION as int + buildToolsVersion = NS_DEFAULT_BUILD_TOOLS_VERSION as String sourceSets { main { @@ -67,24 +89,13 @@ android { if (hasNdkVersion) { ndkVersion ndkVersion } else { - ndkVersion "21.1.6352462" - // ndkVersion "22.1.7171670" + ndkVersion defaultNdkVersion } defaultConfig { minSdkVersion NS_DEFAULT_MIN_SDK_VERSION as int targetSdkVersion NS_DEFAULT_COMPILE_SDK_VERSION as int - if (!optimized && !optimizedWithInspector) { - project.archivesBaseName = "${archivesBaseName}-regular" - } else { - if (optimized) { - project.archivesBaseName = "${archivesBaseName}-optimized" - } else if (optimizedWithInspector) { - project.archivesBaseName = "${archivesBaseName}-optimized-with-inspector" - } - } - externalNativeBuild { cmake { @@ -102,21 +113,26 @@ android { // // arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_static", "-DANDROID_NDK_ROOT=${NDK_PATH}" - cppFlags "-std=c++14" - arguments "-DANDROID_STL=c++_shared", "-DANDROID_NDK_ROOT=${NDK_PATH}" + cppFlags "-std=c++20" + arguments "-DANDROID_STL=c++_static", "-DANDROID_NDK_ROOT=${NDK_PATH}", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" } } ndk { minSdkVersion NS_DEFAULT_MIN_SDK_VERSION as int - if (onlyX86) { - abiFilters 'x86' - } else { - abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' - } + if (onlyX86) { + abiFilters 'x86' + } else { + abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' + } } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + buildTypes { release { minifyEnabled false @@ -133,11 +149,13 @@ android { } allprojects { - gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:all" << "-Werror" - } + afterEvaluate { + tasks.withType(JavaCompile).configureEach { + // remove after "-Xlint:-classfile" https://issuetracker.google.com/issues/359561906 + // todo remove "-Xlint:-this-escape" after updating runtime-binding-generator + options.compilerArgs << "-Xlint:all" << "-Werror" << "-Xlint:-classfile" << "-Xlint:-this-escape" } + } } dependencies { @@ -148,15 +166,16 @@ dependencies { testImplementation "org.mockito:mockito-core:${ns_default_mockito_core_version}" } -tasks.whenTaskAdded { task -> + +tasks.configureEach { task -> def taskName = task.getName() - // println "\t ~ [DEBUG][runtime] build.gradle whenTaskAdded taskName = ${taskName}" + // println "\t ~ [DEBUG][runtime] build.gradle whenTaskAdded taskName = ${taskName}" if (taskName.contains("preReleaseBuild")) { setRuntimeCommit.dependsOn(setPackageVersion) task.dependsOn(setRuntimeCommit) } - if(taskName.contains("bundleReleaseAar")){ + if (taskName.contains("bundleReleaseAar")) { task.dependsOn("testDebugUnitTest") } @@ -166,9 +185,77 @@ tasks.whenTaskAdded { task -> if ((taskName == "bundleDebug") || (taskName == "bundleRelease")) { task.finalizedBy createPackageConfigFileTask(taskName) } + + if (task =~ /configureCMake.*/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /buildCMake.*/) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("syncReleaseLibJars") || taskName.contains("syncDebugLibJars")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("mergeReleaseJniLibFolders") || taskName.contains("mergeDebugJniLibFolders")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("mergeReleaseShaders") || taskName.contains("mergeDebugShaders")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("packageReleaseAssets") || taskName.contains("packageDebugAssets")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("copyReleaseJniLibsProjectOnly") || taskName.contains("copyDebugJniLibsProjectOnly")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("copyReleaseJniLibsProjectAndLocalJars") || taskName.contains("copyDebugJniLibsProjectAndLocalJars")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("generateReleaseLintVitalModel") || taskName.contains("generateDebugLintVitalModel")) { + task.finalizedBy(":app:buildMetadata") + } + + if (taskName.contains("lintVitalAnalyzeRelease") || taskName.contains("lintVitalAnalyzeDebug")) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /lintAnalyze.+AndroidTest/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /compile.+UnitTestJavaWithJavac/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /generate.+LintModel/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /process.+Manifest/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /merge.+Resources/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /verify.+Resources/) { + task.finalizedBy(":app:buildMetadata") + } + + if (task =~ /test.+UnitTest/) { + task.finalizedBy(":app:buildMetadata") + } } -task setPackageVersion { +task 'setPackageVersion' { onlyIf { project.hasProperty('packageVersion') } @@ -183,7 +270,7 @@ task setPackageVersion { } } -task setRuntimeCommit { +task 'setRuntimeCommit' { onlyIf { project.hasProperty('gitCommitVersion') } diff --git a/test-app/runtime/src/main/cpp/ArgConverter.cpp b/test-app/runtime/src/main/cpp/ArgConverter.cpp index 6319b44c8..a8ebe3d66 100644 --- a/test-app/runtime/src/main/cpp/ArgConverter.cpp +++ b/test-app/runtime/src/main/cpp/ArgConverter.cpp @@ -200,7 +200,7 @@ ArgConverter::TypeLongOperationsCache* ArgConverter::GetTypeLongCache(v8::Isolat auto itFound = s_type_long_operations_cache.find(isolate); if (itFound == s_type_long_operations_cache.end()) { cache = new TypeLongOperationsCache; - s_type_long_operations_cache.insert(make_pair(isolate, cache)); + s_type_long_operations_cache.emplace(isolate, cache); } else { cache = itFound->second; } @@ -230,4 +230,4 @@ void ArgConverter::onDisposeIsolate(Isolate* isolate) { } } -std::map ArgConverter::s_type_long_operations_cache; \ No newline at end of file +robin_hood::unordered_map ArgConverter::s_type_long_operations_cache; \ No newline at end of file diff --git a/test-app/runtime/src/main/cpp/ArgConverter.h b/test-app/runtime/src/main/cpp/ArgConverter.h index 88f940f21..a9878e211 100644 --- a/test-app/runtime/src/main/cpp/ArgConverter.h +++ b/test-app/runtime/src/main/cpp/ArgConverter.h @@ -64,7 +64,33 @@ class ArgConverter { } } - static std::u16string ConvertToUtf16String(const v8::Local& s); + inline static v8::Local ToV8String(v8::Isolate *isolate, const std::string &value) { + return v8::String::NewFromUtf8(isolate, value.c_str(), v8::NewStringType::kNormal, + (int) value.length()).ToLocalChecked(); + } + + inline static std::string ToString(v8::Isolate *isolate, const v8::Local &value) { + if (value.IsEmpty()) { + return std::string(); + } + + if (value->IsStringObject()) { + v8::Local obj = value.As()->ValueOf(); + return ToString(isolate, obj); + } + + v8::String::Utf8Value result(isolate, value); + + const char *val = *result; + if (val == nullptr) { + return std::string(); + } + + return std::string(*result, result.length()); + } + + + static std::u16string ConvertToUtf16String(const v8::Local& s); inline static jstring ConvertToJavaString(const v8::Local& jsValue) { JEnv env; @@ -124,7 +150,7 @@ class ArgConverter { * "s_type_long_operations_cache" used to keep function * dealing with operations concerning java long -> javascript number. */ - static std::map s_type_long_operations_cache; + static robin_hood::unordered_map s_type_long_operations_cache; }; } diff --git a/test-app/runtime/src/main/cpp/CSSAgentImpl.cpp b/test-app/runtime/src/main/cpp/CSSAgentImpl.cpp deleted file mode 100644 index 184112161..000000000 --- a/test-app/runtime/src/main/cpp/CSSAgentImpl.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// -// Created by pkanev on 5/11/2017. -// - -#include -#include -#include - -#include "CSSAgentImpl.h" -#include "utils/InspectorCommon.h" - -namespace tns { - -namespace CSSAgentState { -static const char cssEnabled[] = "cssEnabled"; -} - -CSSAgentImpl::CSSAgentImpl(V8InspectorSessionImpl* session, - protocol::FrontendChannel* frontendChannel, - protocol::DictionaryValue* state) - : m_session(session), - m_frontend(frontendChannel), - m_state(state), - m_enabled(false) { - Instance = this; -} - -CSSAgentImpl::~CSSAgentImpl() { } - -void CSSAgentImpl::enable(std::unique_ptr callback) { - if (m_enabled) { - callback->sendSuccess(); - return; - } - - m_state->setBoolean(CSSAgentState::cssEnabled, true); - m_enabled = true; - - callback->sendSuccess(); -} - -DispatchResponse CSSAgentImpl::disable() { - if (!m_enabled) { - return DispatchResponse::Success(); - } - - m_state->setBoolean(CSSAgentState::cssEnabled, false); - - m_enabled = false; - - return DispatchResponse::Success(); -} - -// Not supported -DispatchResponse CSSAgentImpl::getMatchedStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle, Maybe>* out_matchedCSSRules, Maybe>* out_pseudoElements, Maybe>* out_inherited, Maybe>* out_cssKeyframesRules) { - //// out_inlineStyle -// auto cssPropsArr = protocol::Array::create(); -// auto shorthandPropArr = protocol::Array::create(); -// auto inlineStyle = protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(cssPropsArr)) -// .setShorthandEntries(std::move(shorthandPropArr)) -// .build(); - - //// out_attributesStyle -// auto attrArr = protocol::Array::create(); -// auto attributeStyle = protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(attrArr)) -// .setShorthandEntries(std::move(protocol::Array::create())) -// .build(); - - //// out_matchedCSSRules -// auto cssSelectorsArr = protocol::Array::create(); -// auto cssSelectorList = protocol::CSS::SelectorList::create() -// .setSelectors(std::move(cssSelectorsArr)) -// .setText("") -// .build(); - -// auto cssRule = protocol::CSS::CSSRule::create() -// .setSelectorList(std::move(cssSelectorList)) -// .setOrigin(protocol::CSS::StyleSheetOriginEnum::Regular) -// .setStyle(std::move(protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(protocol::Array::create())) -// .setShorthandEntries(std::move(protocol::Array::create())) -// .build())) -// .build(); - -// auto rulesMatchedArr = protocol::Array::create(); - - //// out_pseudoElements -// auto pseudoElementsArr = protocol::Array::create(); - - //// out_inherited -// auto inheritedElementsArr = protocol::Array::create(); -// auto inheritedelem = protocol::CSS::InheritedStyleEntry::create() -// .setInlineStyle(std::move(protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(protocol::Array::create())) -// .setShorthandEntries(std::move(protocol::Array::create())) -// .build())) -// .setMatchedCSSRules(std::move(protocol::Array::create())) -// .build(); -// inheritedElementsArr->addItem(std::move(inheritedelem)); - - //// out_cssKeyframesRules -// auto cssKeyFramesRulesArr = protocol::Array::create(); - -// *out_inlineStyle = Maybe(std::move(inlineStyle)); -// *out_attributesStyle = std::move(Maybe(std::move(attributeStyle))); -// *out_matchedCSSRules = std::move(Maybe>(std::move(rulesMatchedArr))); -// *out_cssKeyframesRules = std::move(Maybe>(std::move(cssKeyFramesRulesArr))); -// *out_inherited = std::move(Maybe>(std::move(inheritedElementsArr))); -// *out_pseudoElements = std::move(Maybe>(std::move(pseudoElementsArr))); - - return DispatchResponse::Success(); -} - -DispatchResponse CSSAgentImpl::getInlineStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle) { - //// out_inlineStyle -// auto cssPropsArr = protocol::Array::create(); -// auto shorthandPropArr = protocol::Array::create(); - -// auto inlineStyle = protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(cssPropsArr)) -// .setShorthandEntries(std::move(shorthandPropArr)) -// .build(); - - //// out_attributesStyle -// auto attrArr = protocol::Array::create(); -// auto attributeStyle = protocol::CSS::CSSStyle::create() -// .setCssProperties(std::move(attrArr)) -// .setShorthandEntries(std::move(protocol::Array::create())) -// .build(); - -// *out_inlineStyle = std::move(Maybe(std::move(inlineStyle))); -// *out_attributesStyle = std::move(Maybe(std::move(attributeStyle))); - - return DispatchResponse::Success(); -} - -DispatchResponse CSSAgentImpl::getComputedStyleForNode(int in_nodeId, std::unique_ptr>* out_computedStyle) { - auto computedStylePropertyArr = std::make_unique>(); - - std::string getComputedStylesForNodeString = "getComputedStylesForNode"; - // TODO: Pete: Find a better way to get a hold of the isolate - auto isolate = v8::Isolate::GetCurrent(); - auto context = isolate->GetCurrentContext(); - auto global = context->Global(); - - auto globalInspectorObject = utils::Common::getGlobalInspectorObject(isolate); - - if (!globalInspectorObject.IsEmpty()) { - v8::Local getComputedStylesForNode; - globalInspectorObject->Get(context, ArgConverter::ConvertToV8String(isolate, getComputedStylesForNodeString)).ToLocal(&getComputedStylesForNode); - - if (!getComputedStylesForNode.IsEmpty() && getComputedStylesForNode->IsFunction()) { - auto getComputedStylesForNodeFunc = getComputedStylesForNode.As(); - v8::Local args[] = { v8::Number::New(isolate, in_nodeId) }; - v8::TryCatch tc(isolate); - - auto maybeResult = getComputedStylesForNodeFunc->Call(context, global, 1, args); - - if (tc.HasCaught()) { - - *out_computedStyle = std::move(computedStylePropertyArr); - return DispatchResponse::ServerError(utils::Common::getJSCallErrorMessage(getComputedStylesForNodeString, tc.Message()->Get()).c_str()); - } - - v8::Local outResult; - - if (maybeResult.ToLocal(&outResult)) { - auto resultString = outResult->ToString(context).ToLocalChecked(); - v8_inspector::String16 resultProtocolString = v8_inspector::toProtocolString(isolate, resultString); - std::vector cbor; - v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(resultProtocolString.characters16(), resultProtocolString.length()), &cbor); - std::unique_ptr resultJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); - protocol::ErrorSupport errorSupport; - std::unique_ptr> computedStyles = utils::Common::fromValue(resultJson.get(), &errorSupport); - - std::vector json; - v8_crdtp::json::ConvertCBORToJSON(errorSupport.Errors(), &json); - auto errorSupportString = v8_inspector::String16(reinterpret_cast(json.data()), json.size()).utf8(); - if (!errorSupportString.empty()) { - auto errorMessage = "Error while parsing CSSComputedStyleProperty object. "; - DEBUG_WRITE_FORCE("%s Error: %s", errorMessage, errorSupportString.c_str()); - return DispatchResponse::ServerError(errorMessage); - } else { - *out_computedStyle = std::move(computedStyles); - - return DispatchResponse::Success(); - } - } - } - } - - *out_computedStyle = std::move(computedStylePropertyArr); - - return DispatchResponse::Success(); -} - -DispatchResponse CSSAgentImpl::getPlatformFontsForNode(int in_nodeId, std::unique_ptr>* out_fonts) { - auto fontsArr = std::make_unique>(); - auto defaultFont = "System Font"; - fontsArr->emplace_back(std::move(protocol::CSS::PlatformFontUsage::create() - .setFamilyName(defaultFont) - .setGlyphCount(1) - .setIsCustomFont(false) - .build())); - *out_fonts = std::move(fontsArr); - - return DispatchResponse::Success(); -} - -DispatchResponse CSSAgentImpl::getStyleSheetText(const String& in_styleSheetId, String* out_text) { - *out_text = ""; - - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::addRule(const String& in_styleSheetId, const String& in_ruleText, std::unique_ptr in_location, std::unique_ptr* out_rule) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::collectClassNames(const String& in_styleSheetId, std::unique_ptr>* out_classNames) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::createStyleSheet(const String& in_frameId, String* out_styleSheetId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::forcePseudoState(int in_nodeId, std::unique_ptr> in_forcedPseudoClasses) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::getBackgroundColors(int in_nodeId, Maybe>* out_backgroundColors, Maybe* out_computedFontSize, Maybe* out_computedFontWeight) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::getMediaQueries(std::unique_ptr>* out_medias) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setEffectivePropertyValueForNode(int in_nodeId, const String& in_propertyName, const String& in_value) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setKeyframeKey(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_keyText, std::unique_ptr* out_keyText) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setMediaText(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_text, std::unique_ptr* out_media) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setRuleSelector(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_selector, std::unique_ptr* out_selectorList) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setStyleSheetText(const String& in_styleSheetId, const String& in_text, Maybe* out_sourceMapURL) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::setStyleTexts(std::unique_ptr> in_edits, std::unique_ptr>* out_styles) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::startRuleUsageTracking() { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::stopRuleUsageTracking(std::unique_ptr>* out_ruleUsage) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse CSSAgentImpl::takeCoverageDelta(std::unique_ptr>* out_coverage) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -CSSAgentImpl* CSSAgentImpl::Instance = 0; -} // namespace tns diff --git a/test-app/runtime/src/main/cpp/CSSAgentImpl.h b/test-app/runtime/src/main/cpp/CSSAgentImpl.h deleted file mode 100644 index 3438a377f..000000000 --- a/test-app/runtime/src/main/cpp/CSSAgentImpl.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Created by pkanev on 5/11/2017. -// - -#ifndef V8_CSS_AGENT_IMPL_H -#define V8_CSS_AGENT_IMPL_H - -#include -#include - -namespace v8_inspector { -class V8InspectorSessionImpl; -} - -namespace tns { - -namespace protocol = v8_inspector::protocol; -using v8_inspector::protocol::Maybe; -using String = v8_inspector::String16; -using protocol::DispatchResponse; -using v8_inspector::V8InspectorSessionImpl; - -class CSSAgentImpl : public protocol::CSS::Backend { - public: - CSSAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); - - ~CSSAgentImpl() override; - - void enable(std::unique_ptr callback) override; - DispatchResponse disable() override; - DispatchResponse getMatchedStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle, Maybe>* out_matchedCSSRules, Maybe>* out_pseudoElements, Maybe>* out_inherited, Maybe>* out_cssKeyframesRules) override; - DispatchResponse getInlineStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle) override; - DispatchResponse getComputedStyleForNode(int in_nodeId, std::unique_ptr>* out_computedStyle) override; - DispatchResponse getPlatformFontsForNode(int in_nodeId, std::unique_ptr>* out_fonts) override; - DispatchResponse getStyleSheetText(const String& in_styleSheetId, String* out_text) override; - DispatchResponse addRule(const String& in_styleSheetId, const String& in_ruleText, std::unique_ptr in_location, std::unique_ptr* out_rule) override; - DispatchResponse collectClassNames(const String& in_styleSheetId, std::unique_ptr>* out_classNames) override; - DispatchResponse createStyleSheet(const String& in_frameId, String* out_styleSheetId) override; - DispatchResponse forcePseudoState(int in_nodeId, std::unique_ptr> in_forcedPseudoClasses) override; - DispatchResponse getBackgroundColors(int in_nodeId, Maybe>* out_backgroundColors, Maybe* out_computedFontSize, Maybe* out_computedFontWeight) override; - DispatchResponse getMediaQueries(std::unique_ptr>* out_medias) override; - DispatchResponse setEffectivePropertyValueForNode(int in_nodeId, const String& in_propertyName, const String& in_value) override; - DispatchResponse setKeyframeKey(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_keyText, std::unique_ptr* out_keyText) override; - DispatchResponse setMediaText(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_text, std::unique_ptr* out_media) override; - DispatchResponse setRuleSelector(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_selector, std::unique_ptr* out_selectorList) override; - DispatchResponse setStyleSheetText(const String& in_styleSheetId, const String& in_text, Maybe* out_sourceMapURL) override; - DispatchResponse setStyleTexts(std::unique_ptr> in_edits, std::unique_ptr>* out_styles) override; - DispatchResponse startRuleUsageTracking() override; - DispatchResponse stopRuleUsageTracking(std::unique_ptr>* out_ruleUsage) override; - DispatchResponse takeCoverageDelta(std::unique_ptr>* out_coverage) override; - - static CSSAgentImpl* Instance; - protocol::CSS::Frontend m_frontend; - - private: - V8InspectorSessionImpl* m_session; - protocol::DictionaryValue* m_state; - bool m_enabled; - - CSSAgentImpl(const CSSAgentImpl&) = delete; - CSSAgentImpl& operator=(const CSSAgentImpl&) = delete; -}; -} // namespace tns - - -#endif //V8_CSS_AGENT_IMPL_H diff --git a/test-app/runtime/src/main/cpp/CallbackHandlers.cpp b/test-app/runtime/src/main/cpp/CallbackHandlers.cpp index d86348e94..82ee5dcc6 100644 --- a/test-app/runtime/src/main/cpp/CallbackHandlers.cpp +++ b/test-app/runtime/src/main/cpp/CallbackHandlers.cpp @@ -213,7 +213,8 @@ void CallbackHandlers::CallJavaMethod(const Local &caller, const string auto isolate = args.GetIsolate(); - if ((entry != nullptr) && entry->isResolved) { + if ((entry != nullptr) && entry->getIsResolved()) { + auto &entrySignature = entry->getSig(); isStatic = entry->isStatic; if (entry->memberId == nullptr) { @@ -236,14 +237,14 @@ void CallbackHandlers::CallJavaMethod(const Local &caller, const string if (isFromInterface) { auto methodAndClassPair = env.GetInterfaceStaticMethodIDAndJClass(className, methodName, - entry->sig); + entrySignature); entry->memberId = methodAndClassPair.first; clazz = methodAndClassPair.second; } else { - entry->memberId = env.GetStaticMethodID(clazz, methodName, entry->sig); + entry->memberId = env.GetStaticMethodID(clazz, methodName, entrySignature); } } else { - entry->memberId = env.GetMethodID(clazz, methodName, entry->sig); + entry->memberId = env.GetMethodID(clazz, methodName, entrySignature); } if (entry->memberId == nullptr) { @@ -257,14 +258,14 @@ void CallbackHandlers::CallJavaMethod(const Local &caller, const string if (isFromInterface) { auto methodAndClassPair = env.GetInterfaceStaticMethodIDAndJClass(className, methodName, - entry->sig); + entrySignature); entry->memberId = methodAndClassPair.first; clazz = methodAndClassPair.second; } else { - entry->memberId = env.GetStaticMethodID(clazz, methodName, entry->sig); + entry->memberId = env.GetStaticMethodID(clazz, methodName, entrySignature); } } else { - entry->memberId = env.GetMethodID(clazz, methodName, entry->sig); + entry->memberId = env.GetMethodID(clazz, methodName, entrySignature); } if (entry->memberId == nullptr) { @@ -279,9 +280,9 @@ void CallbackHandlers::CallJavaMethod(const Local &caller, const string mid = reinterpret_cast(entry->memberId); clazz = entry->clazz; - sig = &entry->sig; - returnType = &entry->returnType; - retType = entry->retType; + sig = &entrySignature; + returnType = &entry->getReturnType(); + retType = entry->getRetType(); } else { DEBUG_WRITE("Resolving method: %s on className %s", methodName.c_str(), className.c_str()); @@ -685,7 +686,8 @@ int CallbackHandlers::RunOnMainThreadFdCallback(int fd, int events, void *data) Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); Local cb = it->second.callback_.Get(isolate); - v8::Local context = cb->GetCreationContextChecked(); + Runtime* runtime = Runtime::GetRuntime(isolate); + v8::Local context = runtime->GetContext(); Context::Scope context_scope(context); // erase the it here as we're already done with its values and the callback might invalidate the iterator cache_.erase(it); @@ -1025,7 +1027,7 @@ void CallbackHandlers::NewThreadCallback(const v8::FunctionCallbackInfo(isolate, thiz); - id2WorkerMap.insert(make_pair(workerId, persistentWorker)); + id2WorkerMap.emplace(workerId, persistentWorker); DEBUG_WRITE("Called Worker constructor id=%d", workerId); @@ -1740,7 +1742,7 @@ std::atomic_uint64_t CallbackHandlers::frameCallbackCount_ = {0}; int CallbackHandlers::nextWorkerId = 0; -std::map *> CallbackHandlers::id2WorkerMap; +robin_hood::unordered_map *> CallbackHandlers::id2WorkerMap; short CallbackHandlers::MAX_JAVA_STRING_ARRAY_LENGTH = 100; jclass CallbackHandlers::RUNTIME_CLASS = nullptr; diff --git a/test-app/runtime/src/main/cpp/CallbackHandlers.h b/test-app/runtime/src/main/cpp/CallbackHandlers.h index 0ca90e7ac..d079d4730 100644 --- a/test-app/runtime/src/main/cpp/CallbackHandlers.h +++ b/test-app/runtime/src/main/cpp/CallbackHandlers.h @@ -18,6 +18,7 @@ #include #include "NativeScriptAssert.h" #include "NativeScriptException.h" +#include "Runtime.h" namespace tns { class CallbackHandlers { @@ -27,7 +28,7 @@ namespace tns { * Stores persistent handles of all 'Worker' objects initialized on the main thread * Note: No isolates different than that of the main thread should access this map */ - static std::map *> id2WorkerMap; + static robin_hood::unordered_map *> id2WorkerMap; static int nextWorkerId; @@ -364,7 +365,8 @@ namespace tns { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); v8::Local cb = entry->callback_.Get(isolate); - v8::Local context = cb->GetCreationContextChecked(); + Runtime* runtime = Runtime::GetRuntime(isolate); + v8::Local context = runtime->GetContext(); v8::Context::Scope context_scope(context); // we're running the callback now, so it's not scheduled anymore entry->markUnscheduled(); diff --git a/test-app/runtime/src/main/cpp/DOMAgentImpl.cpp b/test-app/runtime/src/main/cpp/DOMAgentImpl.cpp deleted file mode 100644 index d9bde478d..000000000 --- a/test-app/runtime/src/main/cpp/DOMAgentImpl.cpp +++ /dev/null @@ -1,386 +0,0 @@ -// -// Created by pkanev on 4/24/2017. -// - -#include -#include -#include -#include - -#include "DOMAgentImpl.h" -#include "utils/InspectorCommon.h" - -namespace tns { - -namespace DOMAgentState { -static const char domEnabled[] = "domEnabled"; -} - -DOMAgentImpl::DOMAgentImpl(V8InspectorSessionImpl* session, - protocol::FrontendChannel* frontendChannel, - protocol::DictionaryValue* state) - : m_session(session), - m_frontend(frontendChannel), - m_state(state), - m_enabled(false) { - Instance = this; -} - -DOMAgentImpl::~DOMAgentImpl() { } - -DispatchResponse DOMAgentImpl::enable() { - if (m_enabled) { - return DispatchResponse::Success(); - } - - m_state->setBoolean(DOMAgentState::domEnabled, true); - - m_enabled = true; - - return DispatchResponse::Success(); -} - -DispatchResponse DOMAgentImpl::disable() { - if (!m_enabled) { - return DispatchResponse::Success(); - } - - m_state->setBoolean(DOMAgentState::domEnabled, false); - - m_enabled = false; - - return DispatchResponse::Success(); -} - -DispatchResponse DOMAgentImpl::getContentQuads(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr>>* out_quads) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_root) { - std::unique_ptr defaultNode = protocol::DOM::Node::create() - .setNodeId(0) - .setBackendNodeId(0) - .setNodeType(9) - .setNodeName("Frame") - .setLocalName("Frame") - .setNodeValue("") - .build(); - - std::string getDocumentFunctionString = "getDocument"; - // TODO: Pete: Find a better way to get a hold of the isolate - auto isolate = v8::Isolate::GetCurrent(); - auto context = isolate->GetCurrentContext(); - auto global = context->Global(); - - auto globalInspectorObject = utils::Common::getGlobalInspectorObject(isolate); - - if (!globalInspectorObject.IsEmpty()) { - v8::Local getDocument; - globalInspectorObject->Get(context, ArgConverter::ConvertToV8String(isolate, getDocumentFunctionString)).ToLocal(&getDocument); - - if (!getDocument.IsEmpty() && getDocument->IsFunction()) { - auto getDocumentFunc = getDocument.As(); - v8::Local args[] = { }; - v8::TryCatch tc(isolate); - - auto maybeResult = getDocumentFunc->Call(context, global, 0, args); - - if (tc.HasCaught()) { - auto error = utils::Common::getJSCallErrorMessage(getDocumentFunctionString, tc.Message()->Get()); - - *out_root = std::move(defaultNode); - return DispatchResponse::ServerError(error); - } - - v8::Local outResult; - - if (maybeResult.ToLocal(&outResult)) { - auto resultString = ArgConverter::ConvertToUtf16String(outResult->ToString(context).ToLocalChecked()); - - if (!outResult->ToObject(context).ToLocalChecked()->Has(context, ArgConverter::ConvertToV8String(isolate, "backendNodeId")).FromMaybe(false)) { - // Using an older version of the modules which doesn't set the backendNodeId required property - resultString = AddBackendNodeIdProperty(isolate, outResult); - } - - auto resultUtf16Data = resultString.data(); - v8_inspector::String16 resultProtocolString = v8_inspector::String16((const uint16_t*) resultUtf16Data); - std::vector cbor; - v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(resultProtocolString.characters16(), resultProtocolString.length()), &cbor); - std::unique_ptr resultJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); - protocol::ErrorSupport errorSupport; - std::unique_ptr domNode = protocol::DOM::Node::fromValue(resultJson.get(), &errorSupport); - - std::vector json; - v8_crdtp::json::ConvertCBORToJSON(errorSupport.Errors(), &json); - auto errorSupportString = v8_inspector::String16(reinterpret_cast(json.data()), json.size()).utf8(); - if (!errorSupportString.empty()) { - auto errorMessage = "Error while parsing debug `DOM Node` object. "; - DEBUG_WRITE_FORCE("JS Error: %s, Error support: %s", errorMessage, errorSupportString.c_str()); - return DispatchResponse::ServerError(errorMessage); - } else { - *out_root = std::move(domNode); - - return DispatchResponse::Success(); - } - } else { - return DispatchResponse::ServerError("Didn't get a proper result from __getDocument call. Returning empty visual tree."); - } - } - } - - *out_root = std::move(defaultNode); - return DispatchResponse::ServerError("Error getting DOM tree."); -} - -DispatchResponse DOMAgentImpl::removeNode(int in_nodeId) { - std::string removeNodeFunctionString = "removeNode"; - - // TODO: Pete: Find a better way to get a hold of the isolate - auto isolate = v8::Isolate::GetCurrent(); - auto context = isolate->GetCurrentContext(); - auto global = context->Global(); - - auto globalInspectorObject = utils::Common::getGlobalInspectorObject(isolate); - - if (!globalInspectorObject.IsEmpty()) { - v8::Local removeNode; - globalInspectorObject->Get(context, ArgConverter::ConvertToV8String(isolate, removeNodeFunctionString)).ToLocal(&removeNode); - - if (!removeNode.IsEmpty() && removeNode->IsFunction()) { - auto removeNodeFunc = removeNode.As(); - v8::Local args[] = { v8::Number::New(isolate, in_nodeId) }; - v8::TryCatch tc(isolate); - - removeNodeFunc->Call(context, global, 1, args); - - if (tc.HasCaught()) { - auto error = utils::Common::getJSCallErrorMessage(removeNodeFunctionString, tc.Message()->Get()); - return DispatchResponse::ServerError(error); - } - - return DispatchResponse::Success(); - } - } - - return DispatchResponse::ServerError("Couldn't remove the selected DOMNode from the visual tree. Global Inspector object not found."); -} - -DispatchResponse DOMAgentImpl::setAttributeValue(int in_nodeId, const String& in_name, const String& in_value) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setAttributesAsText(int in_nodeId, const String& in_text, Maybe in_name) { - // call modules' View class methods to modify view's attribute - // TODO: Pete: Find a better way to get a hold of the isolate - std::string setAttributeAsTextFunctionString = "setAttributeAsText"; - auto isolate = v8::Isolate::GetCurrent(); - auto context = isolate->GetCurrentContext(); - auto global = context->Global(); - - auto globalInspectorObject = utils::Common::getGlobalInspectorObject(isolate); - - if (!globalInspectorObject.IsEmpty()) { - v8::Local setAttributeAsText; - globalInspectorObject->Get(context, ArgConverter::ConvertToV8String(isolate, setAttributeAsTextFunctionString)).ToLocal(&setAttributeAsText); - - if (!setAttributeAsText.IsEmpty() && setAttributeAsText->IsFunction()) { - auto setAttributeAsTextFunc = setAttributeAsText.As(); - // TODO: Pete: Setting the content to contain utf-16 characters will still output garbage - v8::Local args[] = { - v8::Number::New(isolate, in_nodeId), - v8_inspector::toV8String(isolate, in_text), - v8_inspector::toV8String(isolate, in_name.fromJust()) - }; - v8::TryCatch tc(isolate); - - setAttributeAsTextFunc->Call(context, global, 3, args); - - if (tc.HasCaught()) { - auto error = utils::Common::getJSCallErrorMessage(setAttributeAsTextFunctionString, tc.Message()->Get()); - return DispatchResponse::ServerError(error); - } - - return DispatchResponse::Success(); - } - } - - return DispatchResponse::ServerError("Couldn't change selected DOM node's attribute. Global Inspector object not found."); -} - -DispatchResponse DOMAgentImpl::removeAttribute(int in_nodeId, const String& in_name) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::performSearch(const String& in_query, Maybe in_includeUserAgentShadowDOM, String* out_searchId, int* out_resultCount) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getSearchResults(const String& in_searchId, int in_fromIndex, int in_toIndex, std::unique_ptr>* out_nodeIds) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::discardSearchResults(const String& in_searchId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::resolveNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectGroup, Maybe in_executionContextId, std::unique_ptr* out_object) { - auto resolvedNode = protocol::Runtime::RemoteObject::create() - .setType("View") - .build(); - - *out_object = std::move(resolvedNode); - - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::collectClassNamesFromSubtree(int in_nodeId, std::unique_ptr>* out_classNames) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::copyTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::describeNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_node) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::focus(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getAttributes(int in_nodeId, std::unique_ptr>* out_attributes) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getBoxModel(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr* out_model) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getFlattenedDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr>* out_nodes) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getNodeForLocation(int in_x, int in_y, Maybe in_includeUserAgentShadowDOM, int* out_backendNodeId, Maybe* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getOuterHTML(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, String* out_outerHTML) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getRelayoutBoundary(int in_nodeId, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::markUndoableState() { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::moveTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::pushNodeByPathToFrontend(const String& in_path, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::pushNodesByBackendIdsToFrontend(std::unique_ptr> in_backendNodeIds, std::unique_ptr>* out_nodeIds) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::querySelector(int in_nodeId, const String& in_selector, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::querySelectorAll(int in_nodeId, const String& in_selector, std::unique_ptr>* out_nodeIds) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::redo() { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::requestChildNodes(int in_nodeId, Maybe in_depth, Maybe in_pierce) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::requestNode(const String& in_objectId, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setFileInputFiles(std::unique_ptr> in_files, Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getFileInfo(const String& in_objectId, String* out_path) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setInspectedNode(int in_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setNodeName(int in_nodeId, const String& in_name, int* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setNodeValue(int in_nodeId, const String& in_value) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::setOuterHTML(int in_nodeId, const String& in_outerHTML) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::undo() { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -DispatchResponse DOMAgentImpl::getFrameOwner(const String& in_frameId, int* out_backendNodeId, Maybe* out_nodeId) { - return utils::Common::protocolCommandNotSupportedDispatchResponse(); -} - -std::u16string DOMAgentImpl::AddBackendNodeIdProperty(v8::Isolate* isolate, v8::Local jsonInput) { - auto scriptSource = - "(function () {" - " function addBackendNodeId(node) {" - " if (!node.backendNodeId) {" - " node.backendNodeId = 0;" - " }" - " if (node.children) {" - " for (var i = 0; i < node.children.length; i++) {" - " addBackendNodeId(node.children[i]);" - " }" - " }" - " }" - " return function(stringifiedNode) {" - " try {" - " const node = JSON.parse(stringifiedNode);" - " addBackendNodeId(node);" - " return JSON.stringify(node);" - " } catch (e) {" - " return stringifiedNode;" - " }" - " }" - "})()"; - - auto source = ArgConverter::ConvertToV8String(isolate, scriptSource); - v8::Local script; - auto context = isolate->GetCurrentContext(); - v8::Script::Compile(context, source).ToLocal(&script); - - v8::Local result; - script->Run(context).ToLocal(&result); - auto addBackendNodeIdFunction = result.As(); - - v8::Local funcArguments[] = { jsonInput }; - v8::Local scriptResult; - addBackendNodeIdFunction->Call(context, context->Global(), 1, funcArguments).ToLocal(&scriptResult); - - auto resultString = ArgConverter::ConvertToUtf16String(scriptResult->ToString(context).ToLocalChecked()); - return resultString; -} - -DOMAgentImpl* DOMAgentImpl::Instance = 0; -} // namespace tns diff --git a/test-app/runtime/src/main/cpp/DOMAgentImpl.h b/test-app/runtime/src/main/cpp/DOMAgentImpl.h deleted file mode 100644 index a09b591f0..000000000 --- a/test-app/runtime/src/main/cpp/DOMAgentImpl.h +++ /dev/null @@ -1,90 +0,0 @@ -// -// Created by pkanev on 4/24/2017. -// - -#ifndef V8_DOM_AGENT_IMPL_H -#define V8_DOM_AGENT_IMPL_H - -#include -#include - -namespace v8_inspector { -class V8InspectorSessionImpl; -} - -namespace tns { - -using v8_inspector::protocol::Maybe; -using String = v8_inspector::String16; -using v8_inspector::protocol::DispatchResponse; -using v8_inspector::V8InspectorSessionImpl; -namespace protocol = v8_inspector::protocol; - -class DOMAgentImpl : public protocol::DOM::Backend { - public: - DOMAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); - - ~DOMAgentImpl() override; - - virtual DispatchResponse enable() override; - virtual DispatchResponse disable() override; - virtual DispatchResponse getContentQuads(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr>>* out_quads) override; - virtual DispatchResponse getDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_root) override; - virtual DispatchResponse removeNode(int in_nodeId) override; - virtual DispatchResponse setAttributeValue(int in_nodeId, const String& in_name, const String& in_value) override; - virtual DispatchResponse setAttributesAsText(int in_nodeId, const String& in_text, Maybe in_name) override; - virtual DispatchResponse removeAttribute(int in_nodeId, const String& in_name) override; - virtual DispatchResponse performSearch(const String& in_query, Maybe in_includeUserAgentShadowDOM, String* out_searchId, int* out_resultCount) override; - virtual DispatchResponse getSearchResults(const String& in_searchId, int in_fromIndex, int in_toIndex, std::unique_ptr>* out_nodeIds) override; - virtual DispatchResponse discardSearchResults(const String& in_searchId) override; - virtual DispatchResponse resolveNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectGroup, Maybe in_executionContextId, std::unique_ptr* out_object) override; - - DispatchResponse collectClassNamesFromSubtree(int in_nodeId, std::unique_ptr>* out_classNames) override; - DispatchResponse copyTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) override; - DispatchResponse describeNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_node) override; - DispatchResponse focus(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) override; - DispatchResponse getAttributes(int in_nodeId, std::unique_ptr>* out_attributes) override; - DispatchResponse getBoxModel(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr* out_model) override; - DispatchResponse getFlattenedDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr>* out_nodes) override; - DispatchResponse getNodeForLocation(int in_x, int in_y, Maybe in_includeUserAgentShadowDOM, int* out_backendNodeId, Maybe* out_nodeId) override; - DispatchResponse getOuterHTML(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, String* out_outerHTML) override; - DispatchResponse getRelayoutBoundary(int in_nodeId, int* out_nodeId) override; - DispatchResponse markUndoableState() override; - DispatchResponse moveTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) override; - DispatchResponse pushNodeByPathToFrontend(const String& in_path, int* out_nodeId) override; - DispatchResponse pushNodesByBackendIdsToFrontend(std::unique_ptr> in_backendNodeIds, std::unique_ptr>* out_nodeIds) override; - DispatchResponse querySelector(int in_nodeId, const String& in_selector, int* out_nodeId) override; - DispatchResponse querySelectorAll(int in_nodeId, const String& in_selector, std::unique_ptr>* out_nodeIds) override; - DispatchResponse redo() override; - DispatchResponse requestChildNodes(int in_nodeId, Maybe in_depth, Maybe in_pierce) override; - DispatchResponse requestNode(const String& in_objectId, int* out_nodeId) override; - DispatchResponse setFileInputFiles(std::unique_ptr> in_files, Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) override; - DispatchResponse getFileInfo(const String& in_objectId, String* out_path) override; - DispatchResponse setInspectedNode(int in_nodeId) override; - DispatchResponse setNodeName(int in_nodeId, const String& in_name, int* out_nodeId) override; - DispatchResponse setNodeValue(int in_nodeId, const String& in_value) override; - DispatchResponse setOuterHTML(int in_nodeId, const String& in_outerHTML) override; - DispatchResponse undo() override; - DispatchResponse getFrameOwner(const String& in_frameId, int* out_backendNodeId, Maybe* out_nodeId) override; - - const bool enabled() { - return m_enabled; - }; - - static DOMAgentImpl* Instance; - protocol::DOM::Frontend m_frontend; - - static std::u16string AddBackendNodeIdProperty(v8::Isolate* isolate, v8::Local jsonInput); - private: - V8InspectorSessionImpl* m_session; - protocol::DictionaryValue* m_state; - - bool m_enabled; - - DOMAgentImpl(const DOMAgentImpl&) = delete; - DOMAgentImpl& operator=(const DOMAgentImpl&) = delete; -}; -} // namespace tns - -#endif //V8_DOM_AGENT_IMPL_H \ No newline at end of file diff --git a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp deleted file mode 100644 index 4f3234350..000000000 --- a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Created by pkanev on 5/10/2017. -// - -// #include -// #include -// #include - -// #include -// #include -// #include -// #include - -#include "DOMDomainCallbackHandlers.h" - -using namespace tns; - -void DOMDomainCallbackHandlers::DocumentUpdatedCallback(const v8::FunctionCallbackInfo& args) { - // auto domAgentInstance = DOMAgentImpl::Instance; - - // if (!domAgentInstance) { - // return; - // } - - // domAgentInstance->m_frontend.documentUpdated(); -} - -void DOMDomainCallbackHandlers::ChildNodeInsertedCallback(const v8::FunctionCallbackInfo& args) { - // try { - // auto domAgentInstance = DOMAgentImpl::Instance; - - // if (!domAgentInstance) { - // return; - // } - - // auto isolate = args.GetIsolate(); - - // v8::HandleScope scope(isolate); - - // if (args.Length() != 3 || !(args[0]->IsNumber() && args[1]->IsNumber() && args[2]->IsString())) { - // throw NativeScriptException("Calling ChildNodeInserted with invalid arguments. Required params: parentId: number, lastId: number, node: JSON String"); - // } - - // auto context = isolate->GetCurrentContext(); - // auto parentId = args[0]->ToNumber(context).ToLocalChecked(); - // auto lastId = args[1]->ToNumber(context).ToLocalChecked(); - // auto node = args[2]->ToString(context).ToLocalChecked(); - - // auto resultString = DOMAgentImpl::AddBackendNodeIdProperty(isolate, node); - // auto nodeUtf16Data = resultString.data(); - // const v8_inspector::String16& nodeString16 = v8_inspector::String16((const uint16_t*) nodeUtf16Data); - // std::vector cbor; - // v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(nodeString16.characters16(), nodeString16.length()), &cbor); - // std::unique_ptr protocolNodeJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); - - // v8_crdtp::ErrorSupport errorSupport; - // auto domNode = protocol::DOM::Node::fromValue(protocolNodeJson.get(), &errorSupport); - - // std::vector json; - // v8_crdtp::json::ConvertCBORToJSON(errorSupport.Errors(), &json); - // auto errorSupportString = String16(reinterpret_cast(json.data()), json.size()).utf8(); - // if (!errorSupportString.empty()) { - // auto errorMessage = "Error while parsing debug `DOM Node` object. "; - // DEBUG_WRITE_FORCE("%s Error: %s", errorMessage, errorSupportString.c_str()); - // return; - // } - - // domAgentInstance->m_frontend.childNodeInserted(parentId->Int32Value(context).ToChecked(), lastId->Int32Value(context).ToChecked(), std::move(domNode)); - // } catch (NativeScriptException& e) { - // e.ReThrowToV8(); - // } catch (std::exception e) { - // std::stringstream ss; - // ss << "Error: c exception: " << e.what() << std::endl; - // NativeScriptException nsEx(ss.str()); - // nsEx.ReThrowToV8(); - // } catch (...) { - // NativeScriptException nsEx(std::string("Error: c exception!")); - // nsEx.ReThrowToV8(); - // } -} - -void DOMDomainCallbackHandlers::ChildNodeRemovedCallback(const v8::FunctionCallbackInfo& args) { - // try { - // auto domAgentInstance = DOMAgentImpl::Instance; - - // if (!domAgentInstance) { - // return; - // } - - // auto isolate = args.GetIsolate(); - - // v8::HandleScope scope(isolate); - - // if (args.Length() != 2 || !(args[0]->IsNumber() && args[1]->IsNumber())) { - // throw NativeScriptException("Calling ChildNodeRemoved with invalid arguments. Required params: parentId: number, nodeId: number"); - // } - - // auto context = isolate->GetCurrentContext(); - // auto parentId = args[0]->ToNumber(context).ToLocalChecked(); - // auto nodeId = args[1]->ToNumber(context).ToLocalChecked(); - - // domAgentInstance->m_frontend.childNodeRemoved(parentId->Int32Value(context).ToChecked(), nodeId->Int32Value(context).ToChecked()); - // } catch (NativeScriptException& e) { - // e.ReThrowToV8(); - // } catch (std::exception e) { - // std::stringstream ss; - // ss << "Error: c exception: " << e.what() << std::endl; - // NativeScriptException nsEx(ss.str()); - // nsEx.ReThrowToV8(); - // } catch (...) { - // NativeScriptException nsEx(std::string("Error: c exception!")); - // nsEx.ReThrowToV8(); - // } -} - -void DOMDomainCallbackHandlers::AttributeModifiedCallback(const v8::FunctionCallbackInfo& args) { - // try { - // auto domAgentInstance = DOMAgentImpl::Instance; - - // if (!domAgentInstance) { - // return; - // } - - // auto isolate = args.GetIsolate(); - - // v8::HandleScope scope(isolate); - - // if (args.Length() != 3 || !(args[0]->IsNumber() && args[1]->IsString() && args[2]->IsString())) { - // throw NativeScriptException("Calling AttributeModified with invalid arguments. Required params: nodeId: number, name: string, value: string"); - // } - - // auto context = isolate->GetCurrentContext(); - // auto nodeId = args[0]->ToNumber(context).ToLocalChecked(); - // auto attributeName = args[1]->ToString(context).ToLocalChecked(); - // auto attributeValue = args[2]->ToString(context).ToLocalChecked(); - - // domAgentInstance->m_frontend.attributeModified(nodeId->Int32Value(context).ToChecked(), - // v8_inspector::toProtocolString(isolate, attributeName), - // v8_inspector::toProtocolString(isolate, attributeValue)); - // } catch (NativeScriptException& e) { - // e.ReThrowToV8(); - // } catch (std::exception e) { - // std::stringstream ss; - // ss << "Error: c exception: " << e.what() << std::endl; - // NativeScriptException nsEx(ss.str()); - // nsEx.ReThrowToV8(); - // } catch (...) { - // NativeScriptException nsEx(std::string("Error: c exception!")); - // nsEx.ReThrowToV8(); - // } -} - -void DOMDomainCallbackHandlers::AttributeRemovedCallback(const v8::FunctionCallbackInfo& args) { - // try { - // auto domAgentInstance = DOMAgentImpl::Instance; - - // if (!domAgentInstance) { - // return; - // } - // auto isolate = args.GetIsolate(); - - // v8::HandleScope scope(isolate); - - // if (args.Length() != 2 || !(args[0]->IsNumber() && args[1]->IsString())) { - // throw NativeScriptException("Calling AttributeRemoved with invalid arguments. Required params: nodeId: number, name: string"); - // } - - // auto context = isolate->GetCurrentContext(); - // auto nodeId = args[0]->ToNumber(context).ToLocalChecked(); - // auto attributeName = args[1]->ToString(context).ToLocalChecked(); - - // domAgentInstance->m_frontend.attributeRemoved(nodeId->Int32Value(context).ToChecked(), - // v8_inspector::toProtocolString(isolate, attributeName)); - // } catch (NativeScriptException& e) { - // e.ReThrowToV8(); - // } catch (std::exception e) { - // std::stringstream ss; - // ss << "Error: c exception: " << e.what() << std::endl; - // NativeScriptException nsEx(ss.str()); - // nsEx.ReThrowToV8(); - // } catch (...) { - // NativeScriptException nsEx(std::string("Error: c exception!")); - // nsEx.ReThrowToV8(); - // } -} diff --git a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h deleted file mode 100644 index b36a57759..000000000 --- a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Created by pkanev on 5/10/2017. -// - -#ifndef DOMDOMAINCALLBACKHANDLERS_H -#define DOMDOMAINCALLBACKHANDLERS_H - -#include -// #include "DOMAgentImpl.h" -// #include "JsV8InspectorClient.h" -// #include "NativeScriptException.h" - -namespace tns { -class DOMDomainCallbackHandlers { - - public: - static void DocumentUpdatedCallback(const v8::FunctionCallbackInfo& args); - static void ChildNodeInsertedCallback(const v8::FunctionCallbackInfo& args); - static void ChildNodeRemovedCallback(const v8::FunctionCallbackInfo& args); - static void AttributeModifiedCallback(const v8::FunctionCallbackInfo& args); - static void AttributeRemovedCallback(const v8::FunctionCallbackInfo& args); -}; -} - - -#endif //DOMDOMAINCALLBACKHANDLERS_H diff --git a/test-app/runtime/src/main/cpp/FieldAccessor.cpp b/test-app/runtime/src/main/cpp/FieldAccessor.cpp index f8f7148c1..51b3531dd 100644 --- a/test-app/runtime/src/main/cpp/FieldAccessor.cpp +++ b/test-app/runtime/src/main/cpp/FieldAccessor.cpp @@ -19,8 +19,10 @@ Local FieldAccessor::GetJavaField(Isolate* isolate, const Local& JniLocalRef targetJavaObject; - const auto& fieldTypeName = fieldData->signature; - auto isStatic = fieldData->isStatic; + auto &fieldMetadata = fieldData->metadata; + + const auto& fieldTypeName = fieldMetadata.getSig(); + auto isStatic = fieldMetadata.isStatic; auto isPrimitiveType = fieldTypeName.size() == 1; auto isFieldArray = fieldTypeName[0] == '['; @@ -35,11 +37,11 @@ Local FieldAccessor::GetJavaField(Isolate* isolate, const Local& ("L" + fieldTypeName + ";")); if (isStatic) { - fieldData->clazz = env.FindClass(fieldData->declaringType); - fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig); + fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType()); + fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig); } else { - fieldData->clazz = env.FindClass(fieldData->declaringType); - fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig); + fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType()); + fieldData->fid = env.GetFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig); } } @@ -48,7 +50,7 @@ Local FieldAccessor::GetJavaField(Isolate* isolate, const Local& if (targetJavaObject.IsNull()) { stringstream ss; - ss << "Cannot access property '" << fieldData->name.c_str() << "' because there is no corresponding Java object"; + ss << "Cannot access property '" << fieldMetadata.name.c_str() << "' because there is no corresponding Java object"; throw NativeScriptException(ss.str()); } } @@ -186,14 +188,17 @@ Local FieldAccessor::GetJavaField(Isolate* isolate, const Local& void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, const Local& value, FieldCallbackData* fieldData) { JEnv env; + auto &fieldMetadata = fieldData->metadata; + HandleScope handleScope(isolate); auto runtime = Runtime::GetRuntime(isolate); auto objectManager = runtime->GetObjectManager(); JniLocalRef targetJavaObject; - const auto& fieldTypeName = fieldData->signature; - auto isStatic = fieldData->isStatic; + const auto& fieldTypeName = fieldMetadata.getSig(); + auto isStatic = fieldMetadata.isStatic; + auto isPrimitiveType = fieldTypeName.size() == 1; auto isFieldArray = fieldTypeName[0] == '['; @@ -208,14 +213,14 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, ("L" + fieldTypeName + ";")); if (isStatic) { - fieldData->clazz = env.FindClass(fieldData->declaringType); + fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType()); assert(fieldData->clazz != nullptr); - fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig); + fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig); assert(fieldData->fid != nullptr); } else { - fieldData->clazz = env.FindClass(fieldData->declaringType); + fieldData->clazz = env.FindClass(fieldMetadata.getDeclaringType()); assert(fieldData->clazz != nullptr); - fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig); + fieldData->fid = env.GetFieldID(fieldData->clazz, fieldMetadata.name, fieldJniSig); assert(fieldData->fid != nullptr); } } @@ -225,7 +230,7 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, if (targetJavaObject.IsNull()) { stringstream ss; - ss << "Cannot access property '" << fieldData->name.c_str() << "' because there is no corresponding Java object"; + ss << "Cannot access property '" << fieldMetadata.name.c_str() << "' because there is no corresponding Java object"; throw NativeScriptException(ss.str()); } } diff --git a/test-app/runtime/src/main/cpp/FieldCallbackData.h b/test-app/runtime/src/main/cpp/FieldCallbackData.h index 6712bba42..2f6b0e7e5 100644 --- a/test-app/runtime/src/main/cpp/FieldCallbackData.h +++ b/test-app/runtime/src/main/cpp/FieldCallbackData.h @@ -5,25 +5,16 @@ #include "MetadataEntry.h" namespace tns { -struct FieldCallbackData { - FieldCallbackData(const MetadataEntry& metadata) - : - fid(nullptr), clazz(nullptr) { - name = metadata.name; - signature = metadata.sig; - declaringType = metadata.declaringType; - isStatic = metadata.isStatic; - isFinal = metadata.isFinal; - } + struct FieldCallbackData { + FieldCallbackData(MetadataEntry metadata) + : + metadata(metadata), fid(nullptr), clazz(nullptr) { + } - std::string name; - std::string signature; - std::string declaringType; - bool isStatic; - bool isFinal; - jfieldID fid; - jclass clazz; -}; + MetadataEntry metadata; + jfieldID fid; + jclass clazz; + }; } diff --git a/test-app/runtime/src/main/cpp/IsolateDisposer.cpp b/test-app/runtime/src/main/cpp/IsolateDisposer.cpp index b5453289a..c495f0dbe 100644 --- a/test-app/runtime/src/main/cpp/IsolateDisposer.cpp +++ b/test-app/runtime/src/main/cpp/IsolateDisposer.cpp @@ -9,11 +9,19 @@ #include + namespace tns { void disposeIsolate(v8::Isolate *isolate) { tns::ArgConverter::onDisposeIsolate(isolate); tns::MetadataNode::onDisposeIsolate(isolate); tns::V8GlobalHelpers::onDisposeIsolate(isolate); tns::Console::onDisposeIsolate(isolate); + // clear all isolate bound objects + std::lock_guard lock(isolateBoundObjectsMutex_); + auto it = isolateBoundObjects_.find(isolate); + if (it != isolateBoundObjects_.end()) { + it->second->clear(); + isolateBoundObjects_.erase(it); + } } } diff --git a/test-app/runtime/src/main/cpp/IsolateDisposer.h b/test-app/runtime/src/main/cpp/IsolateDisposer.h index 7ce85997c..7fdf757de 100644 --- a/test-app/runtime/src/main/cpp/IsolateDisposer.h +++ b/test-app/runtime/src/main/cpp/IsolateDisposer.h @@ -5,9 +5,36 @@ #ifndef TEST_APP_ISOLATEDISPOSER_H #define TEST_APP_ISOLATEDISPOSER_H #include "v8.h" +#include "robin_hood.h" +#include +#include +#include namespace tns { void disposeIsolate(v8::Isolate* isolate); + using unique_void_ptr = std::unique_ptr; + template + auto unique_void(T * ptr) -> unique_void_ptr + { + return unique_void_ptr(ptr, [](void const * data) { + T const * p = static_cast(data); + delete p; + }); + } + robin_hood::unordered_map>> isolateBoundObjects_; + std::mutex isolateBoundObjectsMutex_; + template + void registerIsolateBoundObject(v8::Isolate* isolate, T *ptr) { + std::lock_guard lock(isolateBoundObjectsMutex_); + auto it = isolateBoundObjects_.find(isolate); + if (it == isolateBoundObjects_.end()) { + auto vec = std::make_shared>(); + vec->push_back(unique_void(ptr)); + isolateBoundObjects_.emplace(isolate, vec); + } else { + it->second->push_back(unique_void(ptr)); + } + } } #endif //TEST_APP_ISOLATEDISPOSER_H diff --git a/test-app/runtime/src/main/cpp/JEnv.cpp b/test-app/runtime/src/main/cpp/JEnv.cpp index cc6629749..dda0241b4 100644 --- a/test-app/runtime/src/main/cpp/JEnv.cpp +++ b/test-app/runtime/src/main/cpp/JEnv.cpp @@ -769,7 +769,7 @@ jclass JEnv::CheckForClassInCache(const string &className) { jclass JEnv::InsertClassIntoCache(const string &className, jclass &tmp) { auto global_class = reinterpret_cast(m_env->NewGlobalRef(tmp)); - s_classCache.insert(make_pair(className, global_class)); + s_classCache.emplace(className, global_class); m_env->DeleteLocalRef(tmp); return global_class; @@ -788,7 +788,7 @@ jthrowable JEnv::CheckForClassMissingCache(const string &className) { jthrowable JEnv::InsertClassIntoMissingCache(const string &className,const jthrowable &tmp) { auto throwable = reinterpret_cast(m_env->NewGlobalRef(tmp)); - s_missingClasses.insert(make_pair(className, throwable)); + s_missingClasses.emplace(className, throwable); m_env->DeleteLocalRef(tmp); return throwable; @@ -855,8 +855,8 @@ void JEnv::CheckForJavaException() { } JavaVM *JEnv::s_jvm = nullptr; -map JEnv::s_classCache; -map JEnv::s_missingClasses; +robin_hood::unordered_map JEnv::s_classCache; +robin_hood::unordered_map JEnv::s_missingClasses; jclass JEnv::RUNTIME_CLASS = nullptr; jmethodID JEnv::GET_CACHED_CLASS_METHOD_ID = nullptr; diff --git a/test-app/runtime/src/main/cpp/JEnv.h b/test-app/runtime/src/main/cpp/JEnv.h index a85fcc637..9c809449a 100644 --- a/test-app/runtime/src/main/cpp/JEnv.h +++ b/test-app/runtime/src/main/cpp/JEnv.h @@ -2,7 +2,7 @@ #define JENV_H_ #include "jni.h" -#include +#include "robin_hood.h" #include namespace tns { @@ -342,8 +342,8 @@ class JEnv { static jmethodID GET_CACHED_CLASS_METHOD_ID; - static std::map s_classCache; - static std::map s_missingClasses; + static robin_hood::unordered_map s_classCache; + static robin_hood::unordered_map s_missingClasses; }; } diff --git a/test-app/runtime/src/main/cpp/JsArgConverter.cpp b/test-app/runtime/src/main/cpp/JsArgConverter.cpp index 5dfa72fbb..559ea2ef6 100644 --- a/test-app/runtime/src/main/cpp/JsArgConverter.cpp +++ b/test-app/runtime/src/main/cpp/JsArgConverter.cpp @@ -23,7 +23,7 @@ JsArgConverter::JsArgConverter(const Local &caller, m_argsLen = 1 + v8ProvidedArgumentsLength; if (m_argsLen > 0) { - if ((entry != nullptr) && (entry->isResolved)) { + if ((entry != nullptr) && (entry->getIsResolved())) { if (entry->parsedSig.empty()) { JniSignatureParser parser(m_methodSignature); entry->parsedSig = parser.Parse(); @@ -58,7 +58,7 @@ JsArgConverter::JsArgConverter(const v8::FunctionCallbackInfo &args, m_argsLen = !hasImplementationObject ? args.Length() : args.Length() - 1; if (m_argsLen > 0) { - if ((entry != nullptr) && (entry->isResolved)) { + if ((entry != nullptr) && (entry->getIsResolved())) { if (entry->parsedSig.empty()) { JniSignatureParser parser(m_methodSignature); entry->parsedSig = parser.Parse(); diff --git a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp index 4c356324c..d82ffe96c 100644 --- a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp +++ b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp @@ -9,16 +9,18 @@ #include "Runtime.h" #include "NativeScriptException.h" +#include "NativeScriptAssert.h" #include "ArgConverter.h" -#include "DOMDomainCallbackHandlers.h" -#include "NetworkDomainCallbackHandlers.h" +#include "Util.h" +#include "Utils.h" using namespace std; using namespace tns; using namespace v8; using namespace v8_inspector; +using namespace inspector; // Utility functions for converting between inspector StringView and UTF8 string @@ -113,6 +115,79 @@ void JsV8InspectorClient::dispatchMessage(const std::string& message) { auto context = Runtime::GetRuntime(isolate_)->GetContext(); Context::Scope context_scope(context); + std::vector vector = tns::Util::ToVector(message); + StringView messageView(vector.data(), vector.size()); + bool success; + + /* + // livesync uses the inspector socket for HMR/LiveSync... + if(message.find("Page.reload") != std::string::npos) { + success = tns::LiveSync(this->isolate_); + if (!success) { + NSLog(@"LiveSync failed"); + } + // todo: should we return here, or is it OK to pass onto a possible Page.reload domain handler? + } + */ + + + if(message.find("Tracing.start") != std::string::npos) { + tracing_agent_->start(); + + // echo back the request to notify frontend the action was a success + // todo: send an empty response for the incoming message id instead. + this->sendNotification(StringBuffer::create(messageView)); + return; + } + + if(message.find("Tracing.end") != std::string::npos) { + tracing_agent_->end(); + std::string res = tracing_agent_->getLastTrace(); + tracing_agent_->SendToDevtools(context, res); + return; + } + + + // parse incoming message as JSON + Local arg; + success = v8::JSON::Parse(context, tns::ArgConverter::ConvertToV8String(isolate_, message)).ToLocal(&arg); + + // stop processing invalid messages + if(!success) { + + // NSLog(@"Inspector failed to parse incoming message: %s", message.c_str()); + // ignore failures to parse. + return; + } + + + + + // Pass incoming message to a registerd domain handler if any + if(!arg.IsEmpty() && arg->IsObject()) { + Local domainDebugger; + Local argObject = arg.As(); + Local domainMethodFunc = GetDebuggerFunctionFromObject(context, argObject, domainDebugger); + + Local result; + success = this->CallDomainHandlerFunction(context, domainMethodFunc, argObject, domainDebugger, result); + + if(success) { + auto requestId = arg.As()->Get(context, tns::ArgConverter::ConvertToV8String(isolate_, "id")).ToLocalChecked(); + auto returnString = GetReturnMessageFromDomainHandlerResult(result, requestId); + + if(returnString.size() > 0) { + std::vector vector_ = tns::Util::ToVector(returnString); + StringView messageView_(vector_.data(), vector_.size()); + auto msg = StringBuffer::create(messageView_); + this->sendNotification(std::move(msg)); + } + return; + } + } + + + doDispatchMessage(message); // TODO: check why this is needed (it should trigger automatically when script depth is 0) isolate_->PerformMicrotaskCheckpoint(); @@ -195,6 +270,15 @@ void JsV8InspectorClient::init() { context_.Reset(isolate_, context); createInspectorSession(); + + tracing_agent_.reset(new tns::inspector::TracingAgentImpl()); + + try { + this->registerModules(); + } catch (NativeScriptException& e) { + // we don't want to throw if registering modules failed. + // e.ReThrowToV8(); + } } JsV8InspectorClient* JsV8InspectorClient::GetInstance() { @@ -221,7 +305,7 @@ void JsV8InspectorClient::inspectorSendEventCallback(const FunctionCallbackInfo< // TODO: ios uses this method, but doesn't work on android // so I'm just sending directly to the socket (which seems to work) - //instance->dispatchMessage(message); + instance->dispatchMessage(message); } void JsV8InspectorClient::sendToFrontEndCallback(const v8::FunctionCallbackInfo& args) { @@ -280,30 +364,164 @@ void JsV8InspectorClient::consoleLogCallback(Isolate* isolate, ConsoleAPIType me session->runtimeAgent()->messageAdded(msg.get()); } -void JsV8InspectorClient::attachInspectorCallbacks(Isolate* isolate, - Local& globalObjectTemplate) { - v8::HandleScope scope(isolate); - - auto inspectorJSObject = ObjectTemplate::New(isolate); - - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "responseReceived"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::ResponseReceivedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "requestWillBeSent"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::RequestWillBeSentCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "dataForRequestId"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::DataForRequestIdCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "loadingFinished"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::LoadingFinishedCallback)); - inspectorJSObject->SetAccessor(ArgConverter::ConvertToV8String(isolate, "isConnected"), JsV8InspectorClient::InspectorIsConnectedGetterCallback); +void JsV8InspectorClient::registerDomainDispatcherCallback(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + std::string domain = tns::ArgConverter::ToString(isolate, args[0].As()); + auto it = Domains.find(domain); + if (it == Domains.end()) { + Local domainCtorFunc = args[1].As(); + Local context = isolate->GetCurrentContext(); + Local ctorArgs[0]; + Local domainInstance; + bool success = domainCtorFunc->CallAsConstructor(context, 0, ctorArgs).ToLocal(&domainInstance); + assert(success && domainInstance->IsObject()); + + Local domainObj = domainInstance.As(); + Persistent* poDomainObj = new Persistent(isolate, domainObj); + Domains.emplace(domain, poDomainObj); + } +} - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "documentUpdated"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::DocumentUpdatedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeInserted"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeInsertedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeRemovedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeModified"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeModifiedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeRemovedCallback)); +void JsV8InspectorClient::inspectorTimestampCallback(const FunctionCallbackInfo& args) { + double timestamp = std::chrono::seconds(std::chrono::seconds(std::time(NULL))).count(); + args.GetReturnValue().Set(timestamp); +} - globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__inspector"), inspectorJSObject); - globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__inspectorSendEvent"), FunctionTemplate::New(isolate, JsV8InspectorClient::inspectorSendEventCallback)); +void JsV8InspectorClient::registerModules() { + DEBUG_WRITE("Registering inspector modules"); + Isolate* isolate = isolate_; + auto rt = Runtime::GetRuntime(isolate); + v8::Locker l(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handleScope(isolate); + auto ctx = rt->GetContext(); + v8::Context::Scope context_scope(ctx); + + Local context = isolate->GetEnteredOrMicrotaskContext(); + Local global = context->Global(); + Local inspectorObject = Object::New(isolate); + + bool success; + Local func; + + // __inspector + success = global->Set(context, ArgConverter::ConvertToV8String(isolate, "__inspector"), inspectorObject).FromMaybe(false); + assert(success); + + // __registerDomainDispatcher + success = v8::Function::New(context, registerDomainDispatcherCallback).ToLocal(&func); + assert(success); + success = global->Set(context, ArgConverter::ConvertToV8String(isolate, "__registerDomainDispatcher"), func).FromMaybe(false); + assert(success); + + // __inspectorSendEvent + Local data = External::New(isolate, this); + success = v8::Function::New(context, inspectorSendEventCallback, data).ToLocal(&func); + assert(success); + success = global->Set(context, ArgConverter::ConvertToV8String(isolate, "__inspectorSendEvent"), func).FromMaybe(false); + assert(success); + + // __inspectorTimestamp + success = v8::Function::New(context, inspectorTimestampCallback).ToLocal(&func); + assert(success); + success = global->Set(context, ArgConverter::ConvertToV8String(isolate, "__inspectorTimestamp"), func).FromMaybe(false); + assert(success); + + TryCatch tc(isolate); + Runtime::GetRuntime(isolate)->RunModule("inspector_modules"); + + if(tc.HasCaught()) { + throw NativeScriptException(tc, "Error loading inspector modules"); + } } + void JsV8InspectorClient::InspectorIsConnectedGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info) { info.GetReturnValue().Set(JsV8InspectorClient::GetInstance()->isConnected_); } JsV8InspectorClient* JsV8InspectorClient::instance = nullptr; + + +bool JsV8InspectorClient::CallDomainHandlerFunction(Local context, Local domainMethodFunc, const Local& arg, Local& domainDebugger, Local& result) { + if(domainMethodFunc.IsEmpty() || !domainMethodFunc->IsFunction()) { + return false; + } + + bool success; + Isolate* isolate = this->isolate_; + TryCatch tc(isolate); + + Local params; + success = arg.As()->Get(context, tns::ArgConverter::ConvertToV8String(isolate, "params")).ToLocal(¶ms); + + if(!success) { + return false; + } + + Local args[2] = { params, arg }; + success = domainMethodFunc->Call(context, domainDebugger, 2, args).ToLocal(&result); + + if (tc.HasCaught()) { + std::string error = tns::ArgConverter::ToString(isolate_, tc.Message()->Get()); + + // backwards compatibility + if(error.find("may be enabled at a time") != std::string::npos) { + // not returning false here because we are catching bogus errors from core... + // Uncaught Error: One XXX may be enabled at a time... + result = v8::Boolean::New(isolate, true); + return true; + } + + // log any other errors - they are caught, but still make them visible to the user. + // tns::LogError(isolate, tc); + + return false; + } + + return success; +} + +std::string JsV8InspectorClient::GetReturnMessageFromDomainHandlerResult(const Local& result, const Local& requestId) { + if(result.IsEmpty() || !(result->IsBoolean() || result->IsObject() || result->IsNullOrUndefined())) { + return ""; + } + + Isolate* isolate = this->isolate_; + + if(!result->IsObject()) { + // if there return value is a "true" boolean or undefined/null we send back an "ack" response with an empty result object + if(result->IsNullOrUndefined() || result->BooleanValue(isolate_)) { + return "{ \"id\":" + tns::ArgConverter::ToString(isolate_, requestId) + ", \"result\": {} }"; + } + + return ""; + } + + v8::Local context = Runtime::GetRuntime(isolate_)->GetContext(); + Local resObject = result.As(); + Local stringified; + + bool success = true; + // already a { result: ... } object + if(resObject->Has(context, tns::ArgConverter::ToV8String(isolate, "result")).ToChecked()) { + success = JSON::Stringify(context, result).ToLocal(&stringified); + } else { + // backwards compatibility - we wrap the response in a new object with the { id, result } keys + // since the returned response only contained the result part. + Context::Scope context_scope(context); + + Local newResObject = v8::Object::New(isolate); + success = success && newResObject->Set(context, tns::ArgConverter::ToV8String(isolate, "id"), requestId).ToChecked(); + success = success && newResObject->Set(context, tns::ArgConverter::ToV8String(isolate, "result"), resObject).ToChecked(); + success = success && JSON::Stringify(context, newResObject).ToLocal(&stringified); + } + + if(!success) { + return ""; + } + + return tns::ArgConverter::ToString(isolate, stringified); +} + +std::map*> JsV8InspectorClient::Domains; diff --git a/test-app/runtime/src/main/cpp/JsV8InspectorClient.h b/test-app/runtime/src/main/cpp/JsV8InspectorClient.h index 53d5c2f28..2b26e5e56 100644 --- a/test-app/runtime/src/main/cpp/JsV8InspectorClient.h +++ b/test-app/runtime/src/main/cpp/JsV8InspectorClient.h @@ -7,6 +7,7 @@ #include "v8.h" #include "JEnv.h" #include "v8-inspector.h" +#include "v8_inspector/ns-v8-tracing-agent-impl.h" using namespace v8_inspector; @@ -21,6 +22,8 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe void disconnect(); void dispatchMessage(const std::string& message); + void registerModules(); + // Overrides of V8Inspector::Channel void sendResponse(int callId, std::unique_ptr message) override; void sendNotification(const std::unique_ptr message) override; @@ -29,16 +32,19 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe static void sendToFrontEndCallback(const v8::FunctionCallbackInfo& args); static void consoleLogCallback(v8::Isolate* isolate, ConsoleAPIType method, const std::vector>& args); static void inspectorSendEventCallback(const v8::FunctionCallbackInfo& args); + static void registerDomainDispatcherCallback(const v8::FunctionCallbackInfo& args); + static void inspectorTimestampCallback(const v8::FunctionCallbackInfo& args); // Overrides of V8InspectorClient void runMessageLoopOnPause(int context_group_id) override; void quitMessageLoopOnPause() override; - static void attachInspectorCallbacks(v8::Isolate* isolate, v8::Local& globalObjectTemplate); static bool inspectorIsConnected() { return JsV8InspectorClient::GetInstance()->isConnected_; } + static std::map*> Domains; + private: JsV8InspectorClient(v8::Isolate* isolate); @@ -53,6 +59,7 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe static JsV8InspectorClient* instance; static constexpr int contextGroupId = 1; + std::unique_ptr tracing_agent_; v8::Isolate* isolate_; std::unique_ptr inspector_; v8::Persistent context_; @@ -65,6 +72,15 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe bool running_nested_loop_ : 1; bool terminated_ : 1; bool isConnected_ : 1; + + + // {N} specific helpers + bool CallDomainHandlerFunction(v8::Local context, + v8::Local domainMethodFunc, + const v8::Local& arg, + v8::Local& domainDebugger, + v8::Local& result); + std::string GetReturnMessageFromDomainHandlerResult(const v8::Local& result, const v8::Local& requestId); }; } diff --git a/test-app/runtime/src/main/cpp/MetadataEntry.cpp b/test-app/runtime/src/main/cpp/MetadataEntry.cpp new file mode 100644 index 000000000..7836dfbfd --- /dev/null +++ b/test-app/runtime/src/main/cpp/MetadataEntry.cpp @@ -0,0 +1,135 @@ +#include "MetadataNode.h" +#include "MetadataEntry.h" +#include "MetadataMethodInfo.h" +#include "MetadataReader.h" + +using namespace tns; + +MetadataEntry::MetadataEntry(MetadataTreeNode *m_treeNode, NodeType nodeType) : + treeNode(m_treeNode), type(nodeType), isExtensionFunction(false), isStatic(false), + isTypeMember(false), memberId(nullptr), clazz(nullptr), mi(nullptr),fi(nullptr), sfi(nullptr), + retType(MethodReturnType::Unknown), + paramCount(-1), isFinal(false), isResolved(false), retTypeParsed(false), + isFinalSet(false), isResolvedSet(false) {} + +std::string &MetadataEntry::getName() { + if (!name.empty()) return name; + + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::Field) { + name = reader->ReadName(fi->nameOffset); + } else if (type == NodeType::StaticField) { + name = reader->ReadName(sfi->nameOffset); + } else if (type == NodeType::Method) { + name = mi.GetName(); + } + + return name; +} + +std::string &MetadataEntry::getSig() { + if (!sig.empty()) return sig; + + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::Field) { + sig = reader->ReadTypeName(fi->nodeId); + } else if (type == NodeType::StaticField) { + sig = reader->ReadTypeName(sfi->nodeId); + } else if (type == NodeType::Method) { + uint8_t sigLength = mi.GetSignatureLength(); + if (sigLength > 0) + sig = mi.GetSignature(); + + } + + return sig; +} + +std::string &MetadataEntry::getReturnType() { + if (!returnType.empty()) return returnType; + + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::Method) { + if (mi.GetSignatureLength() > 0) { + returnType = MetadataReader::ParseReturnType(this->getSig()); + } + } else { + return returnType; + } + + return returnType; +} + +MethodReturnType MetadataEntry::getRetType() { + if (retTypeParsed) return retType; + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::Method && !this->getReturnType().empty()) { + retType = MetadataReader::GetReturnType(this->returnType); + } + + retTypeParsed = true; + + return retType; +} + +std::string &MetadataEntry::getDeclaringType() { + if (!declaringType.empty()) return declaringType; + + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::StaticField) { + declaringType = reader->ReadTypeName(sfi->declaringType); + } else if (type == NodeType::Method && isStatic) { + declaringType = mi.GetDeclaringType(); + } + + return declaringType; +} + +int MetadataEntry::getParamCount() { + if (paramCount != -1) return paramCount; + + auto reader = MetadataNode::getMetadataReader(); + + if (type == NodeType::Method) { + auto sigLength = mi.GetSignatureLength(); + if (sigLength > 0) { + paramCount = sigLength - 1; + } else { + paramCount = 0; + } + } + + return paramCount; +} + +bool MetadataEntry::getIsFinal() { + if (isFinalSet) return isFinal; + + if (type == NodeType::Field) { + isFinal = fi->finalModifier == MetadataTreeNode::FINAL; + } else if (type == NodeType::StaticField) { + isFinal = sfi->finalModifier == MetadataTreeNode::FINAL; + } + + isFinalSet = true; + + return isFinal; +} + +bool MetadataEntry::getIsResolved() { + if (isResolvedSet) return isResolved; + + auto reader = MetadataNode::getMetadataReader(); + if (type == NodeType::Method) { + isResolved = mi.CheckIsResolved() == 1; + } + + isResolvedSet = true; + + return isResolved; +} diff --git a/test-app/runtime/src/main/cpp/MetadataEntry.h b/test-app/runtime/src/main/cpp/MetadataEntry.h index fefa17666..6e708526c 100644 --- a/test-app/runtime/src/main/cpp/MetadataEntry.h +++ b/test-app/runtime/src/main/cpp/MetadataEntry.h @@ -4,56 +4,113 @@ #include #include "jni.h" #include "MetadataTreeNode.h" +#include "MetadataMethodInfo.h" +#include "MetadataFieldInfo.h" namespace tns { -enum class NodeType { - Package, - Class, - Interface, - Method, - Field, - StaticField -}; - -enum class MethodReturnType { - Unknown, - Void, - Byte, - Short, - Int, - Long, - Float, - Double, - Char, - Boolean, - String, - Object -}; - -struct MetadataEntry { - MetadataEntry() - : - isTypeMember(false), name(std::string()), treeNode(nullptr), sig(std::string()), returnType(std::string()), retType(MethodReturnType::Unknown), paramCount(0), - isStatic(false), isFinal(false), declaringType(std::string()), - isResolved(false), isExtensionFunction(false), memberId(nullptr), clazz(nullptr) { - } - MetadataTreeNode* treeNode; - NodeType type; - std::string name; - std::string sig; - std::string returnType; - MethodReturnType retType; - std::string declaringType; - int paramCount; - bool isStatic; - bool isFinal; - bool isTypeMember; - bool isResolved; - bool isExtensionFunction; - void* memberId; - jclass clazz; - std::vector parsedSig; -}; + enum class NodeType { + Package, + Class, + Interface, + Method, + Field, + StaticField + }; + + enum class MethodReturnType { + Unknown, + Void, + Byte, + Short, + Int, + Long, + Float, + Double, + Char, + Boolean, + String, + Object + }; + + class MetadataEntry { + public: + + MetadataEntry(MetadataTreeNode *m_treeNode, NodeType nodeType); + + MetadataEntry(const MetadataEntry &other) = default; + + MetadataEntry &operator=(const MetadataEntry &other) { + if (this != &other) { + treeNode = other.treeNode; + type = other.type; + isExtensionFunction = other.isExtensionFunction; + isStatic = other.isStatic; + isTypeMember = other.isTypeMember; + memberId = other.memberId; + clazz = other.clazz; + parsedSig = other.parsedSig; + mi = other.mi; + fi = other.fi; + sfi = other.sfi; + name = other.name; + sig = other.sig; + returnType = other.returnType; + retType = other.retType; + declaringType = other.declaringType; + paramCount = other.paramCount; + isFinal = other.isFinal; + isResolved = other.isResolved; + isResolvedSet = other.isResolvedSet; + isFinalSet = other.isFinalSet; + } + return *this; + } + + std::string &getName(); + + std::string &getSig(); + + std::string &getReturnType(); + + MethodReturnType getRetType(); + + std::string &getDeclaringType(); + + int getParamCount(); + + bool getIsFinal(); + + bool getIsResolved(); + + MetadataTreeNode *treeNode; + NodeType type; + bool isExtensionFunction; + bool isStatic; + bool isTypeMember; + void *memberId; + jclass clazz; + std::vector parsedSig; + + MethodInfo mi; + FieldInfo *fi; + StaticFieldInfo *sfi; + + std::string name; + std::string sig; + std::string returnType; + MethodReturnType retType; + std::string declaringType; + int paramCount; + bool isFinal; + bool isResolved; + + private: + + bool retTypeParsed; + bool isFinalSet; + bool isResolvedSet; + + }; } #endif /* METADATAENTRY_H_ */ diff --git a/test-app/runtime/src/main/cpp/MetadataMethodInfo.cpp b/test-app/runtime/src/main/cpp/MetadataMethodInfo.cpp index bdd136e92..42289ab89 100644 --- a/test-app/runtime/src/main/cpp/MetadataMethodInfo.cpp +++ b/test-app/runtime/src/main/cpp/MetadataMethodInfo.cpp @@ -1,35 +1,28 @@ #include "MetadataMethodInfo.h" +#include "MetadataNode.h" + using namespace tns; std::string MethodInfo::GetName() { - uint32_t nameOfffset = *reinterpret_cast(m_pData); - string methodName = m_reader->ReadName(nameOfffset); - m_pData += sizeof(uint32_t); - + string methodName = MetadataNode::getMetadataReader()->ReadName(nameOffset); return methodName; } uint8_t MethodInfo::CheckIsResolved() { - auto resolvedData = *reinterpret_cast(m_pData); - m_pData += sizeof(uint8_t); - return resolvedData; } uint16_t MethodInfo::GetSignatureLength() { - m_signatureLength = *reinterpret_cast(m_pData); - m_pData += sizeof(uint16_t); - return m_signatureLength; } std::string MethodInfo::GetSignature() { //use nodeId's to read the whole signature - uint16_t* nodeIdPtr = reinterpret_cast(m_pData); + auto m_reader = MetadataNode::getMetadataReader(); string signature = "("; string ret; for (int i = 0; i < m_signatureLength; i++) { - uint16_t nodeId = *nodeIdPtr++; + uint16_t nodeId = nodeIds[i]; string curArgTypeName = m_reader->ReadTypeName(nodeId); MetadataTreeNode* node = m_reader->GetNodeById(nodeId); @@ -58,23 +51,49 @@ std::string MethodInfo::GetSignature() { //use nodeId's to read the whole signat } signature += ")" + ret; - int sizeofReadNodeIds = m_signatureLength * sizeof(uint16_t); - m_pData += sizeofReadNodeIds; - return signature; } std::string MethodInfo::GetDeclaringType() { - uint16_t* declaringTypePtr = reinterpret_cast(m_pData); - uint16_t nodeId = *declaringTypePtr; + auto m_reader = MetadataNode::getMetadataReader(); - string declTypeName = m_reader->ReadTypeName(nodeId); - - m_pData += sizeof(uint16_t); - - return declTypeName; + return m_reader->ReadTypeName(declaringNodeId); } int MethodInfo::GetSizeOfReadMethodInfo() { + + if (!sizeMeasured) { + sizeMeasured = true; + // name + nameOffset = *reinterpret_cast(m_pData); + m_pData += sizeof(uint32_t); + // resolved data + resolvedData = *reinterpret_cast(m_pData); + m_pData += sizeof(uint8_t); + // sig length + m_signatureLength = *reinterpret_cast(m_pData); + m_pData += sizeof(uint16_t); + + // signature + if (m_signatureLength > 0) { + uint16_t* nodeIdPtr = reinterpret_cast(m_pData); + nodeIds.resize(m_signatureLength); + for (int i = 0; i < m_signatureLength; i++) { + nodeIds[i] = *nodeIdPtr++; + } + m_pData += m_signatureLength * sizeof(uint16_t); + } + + // declaring type + if (isStatic) { + auto declaringTypePtr = reinterpret_cast(m_pData); + declaringNodeId = *declaringTypePtr; + m_pData += sizeof(uint16_t); + } + + + + } + return m_pData - m_pStartData; -} +} \ No newline at end of file diff --git a/test-app/runtime/src/main/cpp/MetadataMethodInfo.h b/test-app/runtime/src/main/cpp/MetadataMethodInfo.h index b3e61bcf1..aadda536e 100644 --- a/test-app/runtime/src/main/cpp/MetadataMethodInfo.h +++ b/test-app/runtime/src/main/cpp/MetadataMethodInfo.h @@ -1,8 +1,6 @@ #ifndef METHODINFOSMARTPOINTER_H_ #define METHODINFOSMARTPOINTER_H_ -#include "MetadataReader.h" - #include #include #include @@ -10,26 +8,59 @@ using namespace std; namespace tns { -class MethodInfo { + class MethodInfo { public: - MethodInfo(uint8_t* pValue, MetadataReader* reader) - : m_pData(pValue), m_pStartData(pValue), m_reader(reader), m_signatureLength(0) { + + MethodInfo(uint8_t *pValue) + : isStatic(false), m_pData(pValue), m_pStartData(pValue), m_signatureLength(0), + sizeMeasured(false), nameOffset(0), resolvedData(0), + declaringNodeId(0){ + } + + MethodInfo(const MethodInfo& other) = default; + + MethodInfo& operator=(const MethodInfo& other) { + if (this != &other) { + isStatic = other.isStatic; + m_pData = other.m_pData; + m_pStartData = other.m_pStartData; + m_signatureLength = other.m_signatureLength; + sizeMeasured = other.sizeMeasured; + nameOffset = other.nameOffset; + resolvedData = other.resolvedData; + declaringNodeId = other.declaringNodeId; + nodeIds = other.nodeIds; + } + return *this; } std::string GetName(); + uint8_t CheckIsResolved(); + uint16_t GetSignatureLength(); + std::string GetSignature(); + std::string GetDeclaringType(); //used only for static methods int GetSizeOfReadMethodInfo(); + bool isStatic; + private: - uint8_t* m_pData; //where we currently read - uint8_t* m_pStartData; // pointer to the beginning + uint8_t *m_pData; //where we currently read + uint8_t *m_pStartData; // pointer to the beginning uint16_t m_signatureLength; - MetadataReader* m_reader; -}; + bool sizeMeasured; + + uint32_t nameOffset; + uint8_t resolvedData; + uint16_t declaringNodeId; + std::vector nodeIds; + + + }; } #endif /* METHODINFOSMARTPOINTER_H_ */ diff --git a/test-app/runtime/src/main/cpp/MetadataNode.cpp b/test-app/runtime/src/main/cpp/MetadataNode.cpp index 9959bf0ea..7d3335fb2 100644 --- a/test-app/runtime/src/main/cpp/MetadataNode.cpp +++ b/test-app/runtime/src/main/cpp/MetadataNode.cpp @@ -97,7 +97,7 @@ MetadataNode* MetadataNode::GetOrCreate(const string& className) { node = GetOrCreateInternal(treeNode); - s_name2NodeCache.insert(make_pair(className, node)); + s_name2NodeCache.emplace(className, node); } else { node = it->second; } @@ -115,7 +115,7 @@ MetadataNode* MetadataNode::GetOrCreateInternal(MetadataTreeNode* treeNode) { } else { result = new MetadataNode(treeNode); - s_treeNode2NodeCache.insert(make_pair(treeNode, result)); + s_treeNode2NodeCache.emplace(treeNode, result); } return result; @@ -131,7 +131,7 @@ MetadataTreeNode* MetadataNode::GetOrCreateTreeNodeByName(const string& classNam } else { result = s_metadataReader.GetOrCreateTreeNodeByName(className); - s_name2TreeNodeCache.insert(make_pair(className, result)); + s_name2TreeNodeCache.emplace(className, result); } return result; @@ -327,10 +327,11 @@ void MetadataNode::FieldAccessorGetterCallback(Local property, const Prope try { auto thiz = info.This(); auto fieldCallbackData = reinterpret_cast(info.Data().As()->Value()); + auto &fieldCallbackMetadata = fieldCallbackData->metadata; - if ((!fieldCallbackData->isStatic && thiz->StrictEquals(info.Holder())) + if ((!fieldCallbackMetadata.isStatic && thiz->StrictEquals(info.Holder())) // check whether there's a declaring type to get the class from it - || (fieldCallbackData->declaringType == "")) { + || (fieldCallbackMetadata.getDeclaringType() == "")) { info.GetReturnValue().SetUndefined(); return; } @@ -354,16 +355,17 @@ void MetadataNode::FieldAccessorSetterCallback(Local property, Local(info.Data().As()->Value()); + auto &fieldCallbackMetadata = fieldCallbackData->metadata; - if (!fieldCallbackData->isStatic && thiz->StrictEquals(info.Holder())) { + if (!fieldCallbackMetadata.isStatic && thiz->StrictEquals(info.Holder())) { auto isolate = info.GetIsolate(); info.GetReturnValue().Set(v8::Undefined(isolate)); return; } - if (fieldCallbackData->isFinal) { + if (fieldCallbackMetadata.getIsFinal()) { stringstream ss; - ss << "You are trying to set \"" << fieldCallbackData->name << "\" which is a final field! Final fields can only be read."; + ss << "You are trying to set \"" << fieldCallbackMetadata.getName() << "\" which is a final field! Final fields can only be read."; string exceptionMessage = ss.str(); throw NativeScriptException(exceptionMessage); @@ -542,7 +544,7 @@ std::vector MetadataNode::SetInstanceMembers( PrototypeTemplateFiller& protoFiller, vector& instanceMethodsCallbackData, const vector& baseInstanceMethodsCallbackData, - MetadataTreeNode* treeNode) { + MetadataTreeNode* treeNode, uint8_t* &curPtr) { auto hasCustomMetadata = treeNode->metadata != nullptr; if (hasCustomMetadata) { @@ -551,10 +553,9 @@ std::vector MetadataNode::SetInstanceMembers( baseInstanceMethodsCallbackData, treeNode); } - SetInstanceFieldsFromStaticMetadata(isolate, protoFiller, treeNode); return SetInstanceMethodsFromStaticMetadata( isolate, ctorFuncTemplate, protoFiller, instanceMethodsCallbackData, - baseInstanceMethodsCallbackData, treeNode); + baseInstanceMethodsCallbackData, treeNode, curPtr); } vector MetadataNode::SetInstanceMethodsFromStaticMetadata( @@ -562,12 +563,12 @@ vector MetadataNode::SetInstanceMethodsFromS PrototypeTemplateFiller& protoFiller, vector &instanceMethodsCallbackData, const vector &baseInstanceMethodsCallbackData, - MetadataTreeNode *treeNode) { + MetadataTreeNode *treeNode, uint8_t* &curPtr) { SET_PROFILER_FRAME(); std::vector instanceMethodData; - uint8_t *curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; + curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; auto nodeType = s_metadataReader.GetNodeType(treeNode); @@ -584,27 +585,28 @@ vector MetadataNode::SetInstanceMethodsFromS auto context = isolate->GetCurrentContext(); - std::unordered_map collectedExtensionMethodDatas; + robin_hood::unordered_map collectedExtensionMethodDatas; auto extensionFunctionsCount = *reinterpret_cast(curPtr); curPtr += sizeof(uint16_t); for (auto i = 0; i < extensionFunctionsCount; i++) { - auto entry = s_metadataReader.ReadExtensionFunctionEntry(&curPtr); + auto entry = MetadataReader::ReadExtensionFunctionEntry(&curPtr); - if (entry.name != lastMethodName) { + auto &methodName = entry.getName(); + if (methodName!= lastMethodName) { // callbackData = tryGetExtensionMethodCallbackData(collectedExtensionMethodDatas, - entry.name); + methodName); if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); - protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData); + protoFiller.FillPrototypeMethod(isolate, methodName, callbackData); - lastMethodName = entry.name; - std::pair p(entry.name, callbackData); - collectedExtensionMethodDatas.insert(p); + lastMethodName = methodName; + std::pair p(methodName, callbackData); + collectedExtensionMethodDatas.emplace(p); } } - callbackData->candidates.push_back(entry); + callbackData->candidates.push_back(std::move(entry)); } @@ -613,19 +615,20 @@ vector MetadataNode::SetInstanceMethodsFromS curPtr += sizeof(uint16_t); for (auto i = 0; i < instanceMethodCount; i++) { - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); + auto entry = MetadataReader::ReadInstanceMethodEntry(&curPtr); // attach a function to the prototype of a javascript Object - if (entry.name != lastMethodName) { + auto &methodName = entry.getName(); + if (methodName != lastMethodName) { // See if we have tracked the callback data before (meaning another version of entry.name exists with different parameters) callbackData = tryGetExtensionMethodCallbackData(collectedExtensionMethodDatas, - entry.name); + methodName); if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); // If we have no tracking of this callback data, create tracking so that we can find it if need be for future itterations where the entry.name is the same... - std::pair p(entry.name, callbackData); - collectedExtensionMethodDatas.insert(p); + std::pair p(methodName, callbackData); + collectedExtensionMethodDatas.emplace(p); } instanceMethodData.push_back(callbackData); @@ -633,8 +636,8 @@ vector MetadataNode::SetInstanceMethodsFromS instanceMethodsCallbackData.push_back(callbackData); auto itBegin = baseInstanceMethodsCallbackData.begin(); auto itEnd = baseInstanceMethodsCallbackData.end(); - auto itFound = find_if(itBegin, itEnd, [&entry](MethodCallbackData *x) { - return x->candidates.front().name == entry.name; + auto itFound = find_if(itBegin, itEnd, [&methodName](MethodCallbackData *x) { + return x->candidates.front().name == methodName; }); if (itFound != itEnd) { callbackData->parent = *itFound; @@ -645,95 +648,43 @@ vector MetadataNode::SetInstanceMethodsFromS Local funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData); auto func = funcTemplate->GetFunction(context).ToLocalChecked(); std::string origin = Constants::APP_ROOT_FOLDER_PATH + GetOrCreateInternal(treeNode)->m_name; - Local wrapperFunc = Wrap(isolate, func, entry.name, origin, + Local wrapperFunc = Wrap(isolate, func, methodName, origin, false /* isCtorFunc */); Local ctorFunc = ctorFuncTemplate->GetFunction(context).ToLocalChecked(); Local protoVal; ctorFunc->Get(context, ArgConverter::ConvertToV8String(isolate, "prototype")).ToLocal( &protoVal); - Local funcName = ArgConverter::ConvertToV8String(isolate, entry.name); + Local funcName = ArgConverter::ConvertToV8String(isolate, methodName); if (!protoVal.IsEmpty() && !protoVal->IsUndefined() && !protoVal->IsNull()) { protoVal.As()->Set(context, funcName, wrapperFunc); } } else { - protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData); + protoFiller.FillPrototypeMethod(isolate, methodName, callbackData); } - lastMethodName = entry.name; + lastMethodName = methodName; } - callbackData->candidates.push_back(entry); - } - - return instanceMethodData; -} - -MetadataNode::MethodCallbackData *MetadataNode::tryGetExtensionMethodCallbackData( - std::unordered_map collectedMethodCallbackDatas, - std::string lookupName) { - - if (collectedMethodCallbackDatas.size() < 1) { - return nullptr; - } - - auto iter = collectedMethodCallbackDatas.find(lookupName); - - if (iter != collectedMethodCallbackDatas.end()) { - return iter->second; - } - - return nullptr; -} - -void MetadataNode::SetInstanceFieldsFromStaticMetadata( - Isolate* isolate, PrototypeTemplateFiller& prototypeTemplate, MetadataTreeNode* treeNode) { - SET_PROFILER_FRAME(); - - Local ctorFunction; - - uint8_t* curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; - - auto nodeType = s_metadataReader.GetNodeType(treeNode); - - auto curType = s_metadataReader.ReadTypeName(treeNode); - - curPtr += sizeof(uint16_t /* baseClassId */); - - if (s_metadataReader.IsNodeTypeInterface(nodeType)) { - curPtr += sizeof(uint8_t) + sizeof(uint32_t); - } - - auto extensionFunctionsCount = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - for (auto i = 0; i < extensionFunctionsCount; i++) { - auto entry = s_metadataReader.ReadExtensionFunctionEntry(&curPtr); - } - - //get candidates from instance methods metadata - auto instanceMethodCout = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - - //skip metadata methods -- advance the pointer only - for (auto i = 0; i < instanceMethodCout; i++) { - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); + callbackData->candidates.push_back(std::move(entry)); } //get candidates from instance fields metadata auto instanceFieldCout = *reinterpret_cast(curPtr); curPtr += sizeof(uint16_t); for (auto i = 0; i < instanceFieldCout; i++) { - auto entry = s_metadataReader.ReadInstanceFieldEntry(&curPtr); + auto entry = MetadataReader::ReadInstanceFieldEntry(&curPtr); + auto fieldName = entry.getName(); auto fieldInfo = new FieldCallbackData(entry); - fieldInfo->declaringType = curType; - prototypeTemplate.FillPrototypeField(isolate, entry.name, fieldInfo); + fieldInfo->metadata.declaringType = curType; + protoFiller.FillPrototypeField(isolate, fieldName, fieldInfo); } auto kotlinPropertiesCount = *reinterpret_cast(curPtr); curPtr += sizeof(uint16_t); for (int i = 0; i < kotlinPropertiesCount; ++i) { - uint32_t nameOfffset = *reinterpret_cast(curPtr); - string propertyName = s_metadataReader.ReadName(nameOfffset); + uint32_t nameOffset = *reinterpret_cast(curPtr); + string propertyName = s_metadataReader.ReadName(nameOffset); curPtr += sizeof(uint32_t); auto hasGetter = *reinterpret_cast(curPtr); @@ -741,8 +692,8 @@ void MetadataNode::SetInstanceFieldsFromStaticMetadata( std::string getterMethodName = ""; if(hasGetter>=1){ - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); - getterMethodName = entry.name; + auto entry = MetadataReader::ReadInstanceMethodEntry(&curPtr); + getterMethodName = entry.getName(); } auto hasSetter = *reinterpret_cast(curPtr); @@ -750,15 +701,35 @@ void MetadataNode::SetInstanceFieldsFromStaticMetadata( std::string setterMethodName = ""; if(hasSetter >= 1){ - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); - setterMethodName = entry.name; + auto entry = MetadataReader::ReadInstanceMethodEntry(&curPtr); + setterMethodName = entry.getName(); } auto propertyInfo = new PropertyCallbackData(propertyName, getterMethodName, setterMethodName); - prototypeTemplate.FillPrototypeProperty(isolate, propertyName, propertyInfo); + protoFiller.FillPrototypeProperty(isolate, propertyName, propertyInfo); } + + return instanceMethodData; +} + +MetadataNode::MethodCallbackData *MetadataNode::tryGetExtensionMethodCallbackData( + const robin_hood::unordered_map &collectedMethodCallbackDatas, + const std::string &lookupName) { + + if (collectedMethodCallbackDatas.empty()) { + return nullptr; + } + + auto iter = collectedMethodCallbackDatas.find(lookupName); + + if (iter != collectedMethodCallbackDatas.end()) { + return iter->second; + } + + return nullptr; } + vector MetadataNode::SetInstanceMembersFromRuntimeMetadata( Isolate* isolate, PrototypeTemplateFiller& protoFiller, vector& instanceMethodsCallbackData, @@ -794,10 +765,10 @@ vector MetadataNode::SetInstanceMembersFromRu // method or field assert((chKind == 'M') || (chKind == 'F')); - MetadataEntry entry; + MetadataEntry entry(nullptr, NodeType::Field); + entry.name = name; entry.sig = signature; - MetadataReader::FillReturnType(entry); entry.paramCount = paramCount; entry.isStatic = false; @@ -819,69 +790,22 @@ vector MetadataNode::SetInstanceMembersFromRu protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData); lastMethodName = entry.name; } - callbackData->candidates.push_back(entry); + callbackData->candidates.push_back(std::move(entry)); } else if (chKind == 'F') { - auto* fieldInfo = new FieldCallbackData(entry); auto access = entry.isFinal ? AccessControl::ALL_CAN_READ : AccessControl::DEFAULT; + auto* fieldInfo = new FieldCallbackData(entry); protoFiller.FillPrototypeField(isolate, entry.name, fieldInfo, access); } } return instanceMethodData; } -void MetadataNode::SetStaticMembers(Isolate* isolate, Local& ctorFunction, MetadataTreeNode* treeNode) { + +void MetadataNode::SetStaticMembers(Isolate* isolate, Local& ctorFunction, MetadataTreeNode* treeNode, uint8_t* &curPtr) { auto hasCustomMetadata = treeNode->metadata != nullptr; auto context = isolate->GetCurrentContext(); if (!hasCustomMetadata) { - uint8_t* curPtr = s_metadataReader.GetValueData() + treeNode->offsetValue + 1; - auto nodeType = s_metadataReader.GetNodeType(treeNode); - auto curType = s_metadataReader.ReadTypeName(treeNode); - curPtr += sizeof(uint16_t /* baseClassId */); - if (s_metadataReader.IsNodeTypeInterface(nodeType)) { - curPtr += sizeof(uint8_t) + sizeof(uint32_t); - } - - auto extensionFunctionsCount = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - for (auto i = 0; i < extensionFunctionsCount; i++) { - auto entry = s_metadataReader.ReadExtensionFunctionEntry(&curPtr); - } - - auto instanceMethodCout = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - for (auto i = 0; i < instanceMethodCout; i++) { - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); - } - - auto instanceFieldCout = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - for (auto i = 0; i < instanceFieldCout; i++) { - auto entry = s_metadataReader.ReadInstanceFieldEntry(&curPtr); - } - - auto kotlinPropertiesCount = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - for (int i = 0; i < kotlinPropertiesCount; ++i) { - uint32_t nameOfffset = *reinterpret_cast(curPtr); - string propertyName = s_metadataReader.ReadName(nameOfffset); - curPtr += sizeof(uint32_t); - - auto hasGetter = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - - if(hasGetter>=1){ - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); - } - - auto hasSetter = *reinterpret_cast(curPtr); - curPtr += sizeof(uint16_t); - - if(hasSetter >= 1){ - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); - } - } - string lastMethodName; MethodCallbackData* callbackData = nullptr; @@ -891,17 +815,18 @@ void MetadataNode::SetStaticMembers(Isolate* isolate, Local& ctorFunct auto staticMethodCout = *reinterpret_cast(curPtr); curPtr += sizeof(uint16_t); for (auto i = 0; i < staticMethodCout; i++) { - auto entry = s_metadataReader.ReadStaticMethodEntry(&curPtr); - if (entry.name != lastMethodName) { + auto entry = MetadataReader::ReadStaticMethodEntry(&curPtr); + auto &methodName = entry.getName(); + if (methodName != lastMethodName) { callbackData = new MethodCallbackData(this); auto funcData = External::New(isolate, callbackData); auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData); auto func = funcTemplate->GetFunction(context).ToLocalChecked(); - auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name); - ctorFunction->Set(context, funcName, Wrap(isolate, func, entry.name, origin, false /* isCtorFunc */)); - lastMethodName = entry.name; + auto funcName = ArgConverter::ConvertToV8String(isolate, methodName); + ctorFunction->Set(context, funcName, Wrap(isolate, func, methodName, origin, false /* isCtorFunc */)); + lastMethodName = methodName; } - callbackData->candidates.push_back(entry); + callbackData->candidates.push_back(std::move(entry)); } //attach .extend function @@ -913,9 +838,9 @@ void MetadataNode::SetStaticMembers(Isolate* isolate, Local& ctorFunct auto staticFieldCout = *reinterpret_cast(curPtr); curPtr += sizeof(uint16_t); for (auto i = 0; i < staticFieldCout; i++) { - auto entry = s_metadataReader.ReadStaticFieldEntry(&curPtr); + auto entry = MetadataReader::ReadStaticFieldEntry(&curPtr); - auto fieldName = ArgConverter::ConvertToV8String(isolate, entry.name); + auto fieldName = ArgConverter::ConvertToV8String(isolate, entry.getName()); auto fieldData = External::New(isolate, new FieldCallbackData(entry)); ctorFunction->SetAccessor(context, fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete); } @@ -929,30 +854,51 @@ void MetadataNode::SetStaticMembers(Isolate* isolate, Local& ctorFunct } } -void MetadataNode::SetInnerTypes(Isolate* isolate, Local& ctorFunction, MetadataTreeNode* treeNode) { - auto context = isolate->GetCurrentContext(); +void MetadataNode::SetInnerTypes(v8::Isolate* isolate, Local& ctorFunction, MetadataTreeNode *treeNode) { if (treeNode->children != nullptr) { - const auto& children = *treeNode->children; - - for (auto curChild : children) { - auto childNode = GetOrCreateInternal(curChild); - - // The call to GetConstructorFunctionTemplate bootstraps the ctor function for the childNode - auto innerTypeCtorFuncTemplate = childNode->GetConstructorFunctionTemplate(isolate, curChild); - if(innerTypeCtorFuncTemplate.IsEmpty()) { - // this class does not exist, so just ignore it - continue; + auto context = isolate->GetCurrentContext(); + const auto &children = *treeNode->children; + for (auto curChild: children) { + bool hasOwnProperty = ctorFunction->HasOwnProperty(context, ArgConverter::ConvertToV8String(isolate, curChild->name)).ToChecked(); + // Child is defined as a function already when the inner type is a companion object + if (!hasOwnProperty) { + ctorFunction->SetAccessor( + context, + v8::String::NewFromUtf8(isolate, curChild->name.c_str()).ToLocalChecked(), + InnerTypeAccessorGetterCallback, nullptr, v8::External::New(isolate, curChild) + ); } - auto innerTypeCtorFunc = Local::New(isolate, *GetOrCreateInternal(curChild)->GetPersistentConstructorFunction(isolate)); - auto innerTypeName = ArgConverter::ConvertToV8String(isolate, curChild->name); - // TODO: remove this once we solve https://github.com/NativeScript/android/pull/1771 - // this avoids a crash, but the companion object is still unaccessible - TryCatch tc(isolate); - ctorFunction->Set(context, innerTypeName, innerTypeCtorFunc); } } } +void MetadataNode::InnerTypeAccessorGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handleScope(isolate); + + MetadataTreeNode* curChild = static_cast(v8::External::Cast(*info.Data())->Value()); + auto childNode = GetOrCreateInternal(curChild); + auto itFound = childNode->m_poCtorCachePerIsolate.find(isolate); + if (itFound != childNode->m_poCtorCachePerIsolate.end()) { + info.GetReturnValue().Set(itFound->second->Get(isolate)); + return; + } + auto innerTypeCtorFuncTemplate= childNode->GetConstructorFunctionTemplate(isolate, curChild); + + if(innerTypeCtorFuncTemplate.IsEmpty()) { + info.GetReturnValue().Set(v8::Undefined(isolate)); + return; + } + + auto innerTypeCtorFunc = Local::New(isolate, *GetOrCreateInternal(curChild)->GetPersistentConstructorFunction(isolate)); + auto innerTypeName = ArgConverter::ConvertToV8String(isolate, curChild->name); + // TODO: remove this once we solve https://github.com/NativeScript/android/pull/1771 + // this avoids a crash, but the companion object is still unaccessible + TryCatch tc(isolate); + info.GetReturnValue().Set(innerTypeCtorFunc); +} + + Local MetadataNode::GetConstructorFunctionTemplate(Isolate* isolate, MetadataTreeNode* treeNode) { std::vector instanceMethodsCallbackData; @@ -993,7 +939,7 @@ Local MetadataNode::GetConstructorFunctionTemplate(Isolate* is ctorFuncTemplate.Clear(); auto pft = new Persistent(isolate, ctorFuncTemplate); CtorCacheData ctorCacheItem(pft, instanceMethodsCallbackData); - cache->CtorFuncCache.insert(make_pair(treeNode, ctorCacheItem)); + cache->CtorFuncCache.emplace(treeNode, ctorCacheItem); return ctorFuncTemplate; } @@ -1034,9 +980,11 @@ Local MetadataNode::GetConstructorFunctionTemplate(Isolate* is PrototypeTemplateFiller protoFiller{ctorFuncTemplate->PrototypeTemplate()}; + uint8_t* curPtr = nullptr; + auto instanceMethodData = node->SetInstanceMembers( isolate, ctorFuncTemplate, protoFiller, instanceMethodsCallbackData, - baseInstanceMethodsCallbackData, treeNode); + baseInstanceMethodsCallbackData, treeNode, curPtr); if (!skippedBaseTypes.empty()) { node->SetMissingBaseMethods(isolate, skippedBaseTypes, instanceMethodData, protoFiller); } @@ -1048,19 +996,19 @@ Local MetadataNode::GetConstructorFunctionTemplate(Isolate* is auto wrappedCtorFunc = Wrap(isolate, ctorFunc, node->m_treeNode->name, origin, true /* isCtorFunc */); - node->SetStaticMembers(isolate, wrappedCtorFunc, treeNode); + node->SetStaticMembers(isolate, wrappedCtorFunc, treeNode, curPtr); // insert isolate-specific persistent function handle node->m_poCtorCachePerIsolate.insert({isolate, new Persistent(isolate, wrappedCtorFunc)}); if (!baseCtorFunc.IsEmpty()) { - auto context = isolate->GetCurrentContext(); - wrappedCtorFunc->SetPrototype(context, baseCtorFunc); + auto currentContext = isolate->GetCurrentContext(); + wrappedCtorFunc->SetPrototype(currentContext, baseCtorFunc); } //cache "ctorFuncTemplate" auto pft = new Persistent(isolate, ctorFuncTemplate); CtorCacheData ctorCacheItem(pft, instanceMethodsCallbackData); - cache->CtorFuncCache.insert(make_pair(treeNode, ctorCacheItem)); + cache->CtorFuncCache.emplace(treeNode, ctorCacheItem); SetInnerTypes(isolate, wrappedCtorFunc, treeNode); @@ -1288,14 +1236,14 @@ void MetadataNode::MethodCallback(const v8::FunctionCallbackInfo& inf // Iterates through all methods and finds the best match based on the number of arguments auto found = false; for (auto& c : candidates) { - found = (!c.isExtensionFunction && c.paramCount == argLength) || ( - c.isExtensionFunction && c.paramCount == argLength + 1); + found = (!c.isExtensionFunction && c.getParamCount() == argLength) || ( + c.isExtensionFunction && c.getParamCount() == argLength + 1); if (found) { if(c.isExtensionFunction){ - className = &c.declaringType; + className = &c.getDeclaringType(); } entry = &c; - DEBUG_WRITE("MetaDataEntry Method %s's signature is: %s", entry->name.c_str(), entry->sig.c_str()); + DEBUG_WRITE("MetaDataEntry Method %s's signature is: %s", entry->name.c_str(), entry->getSig().c_str()); break; } } @@ -1446,9 +1394,9 @@ Local MetadataNode::GetImplementationObject(Isolate* isolate, const Loca //DEBUG_WRITE("GetImplementationObject not found since cycle parents reached abovePrototype:%d", (abovePrototype.IsEmpty() || abovePrototype.As().IsEmpty()) ? -1 : abovePrototype.As()->GetIdentityHash()); return Local(); } else { - Local hiddenVal; - V8GetPrivateValue(isolate, currentPrototype.As(), V8StringConstants::GetClassImplementationObject(isolate), hiddenVal); - auto value = hiddenVal; + Local _hiddenVal; + V8GetPrivateValue(isolate, currentPrototype.As(), V8StringConstants::GetClassImplementationObject(isolate), _hiddenVal); + auto value = _hiddenVal; if (!value.IsEmpty()) { implementationObject = currentPrototype.As(); @@ -1735,11 +1683,11 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfoExtendedCtorFuncCache.insert(make_pair(fullExtendedName, cacheData)); + cache->ExtendedCtorFuncCache.emplace(fullExtendedName, cacheData); if (frame.check()) { frame.log("Extending: " + node->m_name); @@ -1858,24 +1806,26 @@ MetadataNode* MetadataNode::GetNodeFromHandle(const Local& value) { return node; } -MetadataEntry MetadataNode::GetChildMetadataForPackage(MetadataNode* node, const string& propName) { - MetadataEntry child; - +MetadataEntry MetadataNode::GetChildMetadataForPackage(MetadataNode *node, const std::string &propName) { assert(node->m_treeNode->children != nullptr); - const auto& children = *node->m_treeNode->children; + MetadataEntry child(nullptr, NodeType::Class); + + const auto &children = *node->m_treeNode->children; - for (auto treeNodeChild : children) { + for (auto treeNodeChild: children) { if (propName == treeNodeChild->name) { child.name = propName; child.treeNode = treeNodeChild; + child.type = static_cast(s_metadataReader.GetNodeType(treeNodeChild)); - uint8_t childNodeType = s_metadataReader.GetNodeType(treeNodeChild); - if (s_metadataReader.IsNodeTypeInterface(childNodeType)) { + if (s_metadataReader.IsNodeTypeInterface((uint8_t) child.type)) { bool isPrefix; - string declaringType = s_metadataReader.ReadInterfaceImplementationTypeName(treeNodeChild, isPrefix); + string declaringType = s_metadataReader.ReadInterfaceImplementationTypeName( + treeNodeChild, isPrefix); child.declaringType = isPrefix - ? (declaringType + s_metadataReader.ReadTypeName(child.treeNode)) + ? (declaringType + + s_metadataReader.ReadTypeName(child.treeNode)) : declaringType; } } @@ -1918,7 +1868,7 @@ void MetadataNode::BuildMetadata(const string& filesPath) { // startup because the receiver is triggered. So even though we are exiting, the receiver will have // done its job - exit(0); + _Exit(0); } else { throw NativeScriptException(ss.str()); @@ -2027,7 +1977,7 @@ MetadataNode::MetadataNodeCache* MetadataNode::GetMetadataNodeCache(Isolate* iso auto itFound = s_metadata_node_cache.find(isolate); if (itFound == s_metadata_node_cache.end()) { cache = new MetadataNodeCache; - s_metadata_node_cache.insert(make_pair(isolate, cache)); + s_metadata_node_cache.emplace(isolate, cache); } else { cache = itFound->second; } @@ -2038,7 +1988,7 @@ void MetadataNode::EnableProfiler(bool enableProfiler) { s_profilerEnabled = enableProfiler; } -bool MetadataNode::IsJavascriptKeyword(std::string word) { +bool MetadataNode::IsJavascriptKeyword(const std::string &word) { static set keywords; if (keywords.empty()) { @@ -2158,15 +2108,15 @@ void MetadataNode::SetMissingBaseMethods( MethodCallbackData* callbackData = nullptr; for (auto i = 0; i < instanceMethodCount; i++) { - auto entry = s_metadataReader.ReadInstanceMethodEntry(&curPtr); + auto entry = MetadataReader::ReadInstanceMethodEntry(&curPtr); - auto isConstructor = entry.name == ""; + auto isConstructor = entry.getName() == ""; if (isConstructor) { continue; } for (auto data: instanceMethodData) { - if (data->candidates.front().name == entry.name) { + if (data->candidates.front().getName() == entry.getName()) { callbackData = data; break; } @@ -2174,25 +2124,25 @@ void MetadataNode::SetMissingBaseMethods( if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); - protoFiller.FillPrototypeMethod(isolate, entry.name, callbackData); + protoFiller.FillPrototypeMethod(isolate, entry.getName(), callbackData); } bool foundSameSig = false; - for (auto m: callbackData->candidates) { - foundSameSig = m.sig == entry.sig; + for (auto &m: callbackData->candidates) { + foundSameSig = m.sig == entry.getSig(); if (foundSameSig) { break; } } if (!foundSameSig) { - callbackData->candidates.push_back(entry); + callbackData->candidates.push_back(std::move(entry)); } } } } -void MetadataNode::RegisterSymbolHasInstanceCallback(Isolate* isolate, MetadataEntry entry, Local interface) { +void MetadataNode::RegisterSymbolHasInstanceCallback(Isolate* isolate, MetadataEntry& entry, Local interface) { if (interface->IsNullOrUndefined()) { return; } @@ -2247,7 +2197,7 @@ void MetadataNode::SymbolHasInstanceCallback(const v8::FunctionCallbackInfo s; MetadataTreeNode* n = entry.treeNode; while (n != nullptr && n->name != "") { @@ -2291,12 +2241,16 @@ void MetadataNode::onDisposeIsolate(Isolate* isolate) { } } +MetadataReader* MetadataNode::getMetadataReader() { + return &MetadataNode::s_metadataReader; +} + string MetadataNode::TNS_PREFIX = "com/tns/gen/"; MetadataReader MetadataNode::s_metadataReader; -std::map MetadataNode::s_name2NodeCache; -std::map MetadataNode::s_name2TreeNodeCache; -std::map MetadataNode::s_treeNode2NodeCache; -map MetadataNode::s_metadata_node_cache; +robin_hood::unordered_map MetadataNode::s_name2NodeCache; +robin_hood::unordered_map MetadataNode::s_name2TreeNodeCache; +robin_hood::unordered_map MetadataNode::s_treeNode2NodeCache; +robin_hood::unordered_map MetadataNode::s_metadata_node_cache; bool MetadataNode::s_profilerEnabled = false; -std::map*> MetadataNode::s_arrayObjectTemplates; +robin_hood::unordered_map*> MetadataNode::s_arrayObjectTemplates; diff --git a/test-app/runtime/src/main/cpp/MetadataNode.h b/test-app/runtime/src/main/cpp/MetadataNode.h index d66ef0484..71e7bfc05 100644 --- a/test-app/runtime/src/main/cpp/MetadataNode.h +++ b/test-app/runtime/src/main/cpp/MetadataNode.h @@ -60,6 +60,8 @@ class MetadataNode { static std::string GetTypeMetadataName(v8::Isolate* isolate, v8::Local& value); static void onDisposeIsolate(v8::Isolate* isolate); + + static MetadataReader* getMetadataReader(); private: struct MethodCallbackData; @@ -74,30 +76,30 @@ class MetadataNode { MetadataNode(MetadataTreeNode* treeNode); - static bool IsJavascriptKeyword(std::string word); + static bool IsJavascriptKeyword(const std::string &word); v8::Local CreatePackageObject(v8::Isolate* isolate); v8::Local GetConstructorFunction(v8::Isolate* isolate); v8::Local GetConstructorFunctionTemplate(v8::Isolate* isolate, MetadataTreeNode* treeNode); v8::Local GetConstructorFunctionTemplate(v8::Isolate* isolate, MetadataTreeNode* treeNode, std::vector& instanceMethodsCallbackData); v8::Persistent* GetPersistentConstructorFunction(v8::Isolate* isolate); - v8::Local GetOrCreateArrayObjectTemplate(v8::Isolate* isolate); + static v8::Local GetOrCreateArrayObjectTemplate(v8::Isolate* isolate); std::vector SetInstanceMembers( v8::Isolate* isolate, v8::Local& ctorFuncTemplate, PrototypeTemplateFiller& protoFiller, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, - MetadataTreeNode* treeNode); + MetadataTreeNode* treeNode, uint8_t* &curPtr); std::vector SetInstanceMethodsFromStaticMetadata( v8::Isolate* isolate, v8::Local& ctorFuncTemplate, PrototypeTemplateFiller& protoFiller, std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, - MetadataTreeNode* treeNode); - MethodCallbackData* tryGetExtensionMethodCallbackData( - std::unordered_map collectedMethodCallbackDatas, - std::string lookupName); + MetadataTreeNode* treeNode, uint8_t* &curPtr); + static MethodCallbackData* tryGetExtensionMethodCallbackData( + const robin_hood::unordered_map &collectedMethodCallbackDatas, + const std::string &lookupName); void SetInstanceFieldsFromStaticMetadata( v8::Isolate* isolate, PrototypeTemplateFiller& protoFiller, MetadataTreeNode* treeNode); @@ -106,8 +108,10 @@ class MetadataNode { std::vector& instanceMethodsCallbackData, const std::vector& baseInstanceMethodsCallbackData, MetadataTreeNode* treeNode); - void SetStaticMembers(v8::Isolate* isolate, v8::Local& ctorFunction, MetadataTreeNode* treeNode); - void SetInnerTypes(v8::Isolate* isolate, v8::Local& ctorFunction, MetadataTreeNode* treeNode); + + void SetStaticMembers(v8::Isolate* isolate, v8::Local& ctorFunction, MetadataTreeNode* treeNode, uint8_t* &curPtr); + static void InnerTypeAccessorGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info); + static void SetInnerTypes(v8::Isolate* isolate, v8::Local& ctorFunction, MetadataTreeNode* treeNode); static void BuildMetadata(uint32_t nodesLength, uint8_t* nodeData, uint32_t nameLength, uint8_t* nameData, uint32_t valueLength, uint8_t* valueData); @@ -117,7 +121,7 @@ class MetadataNode { static MetadataTreeNode* GetOrCreateTreeNodeByName(const std::string& className); - static MetadataEntry GetChildMetadataForPackage(MetadataNode* node, const std::string& propName); + static MetadataEntry GetChildMetadataForPackage(MetadataNode *node, const std::string &propName); static MetadataNode* GetInstanceMetadata(v8::Isolate* isolate, const v8::Local& value); @@ -157,31 +161,31 @@ class MetadataNode { static bool GetExtendLocation(v8::Isolate* isolate, std::string& extendLocation, bool isTypeScriptExtend); static ExtendedClassCacheData GetCachedExtendedClassData(v8::Isolate* isolate, const std::string& proxyClassName); - static void RegisterSymbolHasInstanceCallback(v8::Isolate* isolate, MetadataEntry entry, v8::Local interface); + static void RegisterSymbolHasInstanceCallback(v8::Isolate* isolate, MetadataEntry& entry, v8::Local interface); static void SymbolHasInstanceCallback(const v8::FunctionCallbackInfo& info); - static std::string GetJniClassName(MetadataEntry entry); + static std::string GetJniClassName(MetadataEntry& entry); - v8::Local Wrap(v8::Isolate* isolate, const v8::Local& function, const std::string& name, const std::string& origin, bool isCtorFunc); + static v8::Local Wrap(v8::Isolate* isolate, const v8::Local& function, const std::string& name, const std::string& origin, bool isCtorFunc); - bool CheckClassHierarchy(JEnv& env, jclass currentClass, MetadataTreeNode* curentTreeNode, MetadataTreeNode* baseTreeNode, std::vector& skippedBaseTypes); + static bool CheckClassHierarchy(JEnv& env, jclass currentClass, MetadataTreeNode* curentTreeNode, MetadataTreeNode* baseTreeNode, std::vector& skippedBaseTypes); void SetMissingBaseMethods(v8::Isolate* isolate, const std::vector& skippedBaseTypes, const std::vector& instanceMethodData, PrototypeTemplateFiller& protoFiller); MetadataTreeNode* m_treeNode; - std::map*> m_poCtorCachePerIsolate; + robin_hood::unordered_map*> m_poCtorCachePerIsolate; std::string m_name; std::string m_implType; bool m_isArray; static std::string TNS_PREFIX; static MetadataReader s_metadataReader; - static std::map s_name2NodeCache; - static std::map s_name2TreeNodeCache; - static std::map s_treeNode2NodeCache; - static std::map s_metadata_node_cache; - static std::map*> s_arrayObjectTemplates; + static robin_hood::unordered_map s_name2NodeCache; + static robin_hood::unordered_map s_name2TreeNodeCache; + static robin_hood::unordered_map s_treeNode2NodeCache; + static robin_hood::unordered_map s_metadata_node_cache; + static robin_hood::unordered_map*> s_arrayObjectTemplates; static bool s_profilerEnabled; struct MethodCallbackData { @@ -263,9 +267,9 @@ class MetadataNode { struct MetadataNodeCache { v8::Persistent* MetadataKey; - std::map CtorFuncCache; + robin_hood::unordered_map CtorFuncCache; - std::map ExtendedCtorFuncCache; + robin_hood::unordered_map ExtendedCtorFuncCache; }; }; } diff --git a/test-app/runtime/src/main/cpp/MetadataReader.cpp b/test-app/runtime/src/main/cpp/MetadataReader.cpp index 282300f56..17b55b799 100644 --- a/test-app/runtime/src/main/cpp/MetadataReader.cpp +++ b/test-app/runtime/src/main/cpp/MetadataReader.cpp @@ -1,22 +1,29 @@ #include "MetadataReader.h" #include "MetadataMethodInfo.h" +#include #include "Util.h" #include using namespace std; using namespace tns; -MetadataReader::MetadataReader() - : - m_nodesLength(0), m_nodeData(nullptr), m_nameLength(0), m_nameData(nullptr), m_valueLength(0), m_valueData(nullptr), m_root(nullptr), m_getTypeMetadataCallback(nullptr) { -} - -MetadataReader::MetadataReader(uint32_t nodesLength, uint8_t* nodeData, uint32_t nameLength, uint8_t* nameData, uint32_t valueLength, uint8_t* valueData, GetTypeMetadataCallback getTypeMetadataCallback) - : - m_nodesLength(nodesLength), m_nodeData(nodeData), m_nameLength(nameLength), m_nameData(nameData), m_valueLength(valueLength), m_valueData(valueData), m_getTypeMetadataCallback(getTypeMetadataCallback) { +MetadataReader::MetadataReader() : m_root(nullptr), m_nodesLength(0), m_nameLength(0), + m_valueLength(0), + m_nodeData(nullptr), m_nameData(nullptr), m_valueData(nullptr), + m_getTypeMetadataCallback(nullptr) {} + +MetadataReader::MetadataReader(uint32_t nodesLength, uint8_t *nodeData, uint32_t nameLength, + uint8_t *nameData, uint32_t valueLength, uint8_t *valueData, + GetTypeMetadataCallback getTypeMetadataCallback) + : + m_nodesLength(nodesLength), m_nodeData(nodeData), m_nameLength(nameLength), + m_nameData(nameData), m_valueLength(valueLength), m_valueData(valueData), + m_getTypeMetadataCallback(getTypeMetadataCallback) { m_root = BuildTree(); } + + // helper debug function when need to convert a metadata node to its full name //std::string toFullName(MetadataTreeNode* p) { // std::string final = p->name; @@ -54,20 +61,28 @@ MetadataTreeNode* MetadataReader::BuildTree() { while (true) { uint16_t childNodeDataId = childNodeData - rootNodeData; + + MetadataTreeNode* childNode; // node (and its next siblings) already visited, so we don't need to visit it again if (m_v[childNodeDataId] != emptyNode) { + childNode = m_v[childNodeDataId]; + __android_log_print(ANDROID_LOG_ERROR, "TNS.error", "Consistency error in metadata. A child should never have been visited before its parent. Parent: %s Child: %s. Child metadata id: %u", node->name.c_str(), childNode->name.c_str(), childNodeDataId); break; + } else { + childNode = new MetadataTreeNode; + childNode->name = ReadName(childNodeData->offsetName); + childNode->offsetValue = childNodeData->offsetValue; } - - MetadataTreeNode* childNode = new MetadataTreeNode; childNode->parent = node; - childNode->name = ReadName(childNodeData->offsetName); - childNode->offsetValue = childNodeData->offsetValue; node->children->push_back(childNode); m_v[childNodeDataId] = childNode; + if (childNodeDataId == childNodeData->nextSiblingId) { + break; + } + childNodeData = rootNodeData + childNodeData->nextSiblingId; } } @@ -78,97 +93,12 @@ MetadataTreeNode* MetadataReader::BuildTree() { return GetNodeById(0); } -void MetadataReader::FillEntryWithFiedldInfo(FieldInfo* fi, MetadataEntry& entry) { - entry.isTypeMember = true; - entry.name = ReadName(fi->nameOffset); - entry.sig = ReadTypeName(fi->nodeId); - entry.isFinal = fi->finalModifier == MetadataTreeNode::FINAL; -} - -void MetadataReader::FillEntryWithMethodInfo(MethodInfo& mi, MetadataEntry& entry) { - entry.type = NodeType::Method; - entry.isTypeMember = true; - entry.name = mi.GetName(); - entry.isResolved = mi.CheckIsResolved() == 1; - uint16_t sigLength = mi.GetSignatureLength(); - assert(sigLength > 0); - entry.paramCount = sigLength - 1; - entry.sig = mi.GetSignature(); - FillReturnType(entry); -} - - -MetadataEntry MetadataReader::ReadInstanceFieldEntry(uint8_t** data) { - FieldInfo* fi = *reinterpret_cast(data); - - MetadataEntry entry; - FillEntryWithFiedldInfo(fi, entry); - entry.isStatic = false; - entry.type = NodeType::Field; - - *data += sizeof(FieldInfo); - - return entry; -} - -MetadataEntry MetadataReader::ReadStaticFieldEntry(uint8_t** data) { - StaticFieldInfo* sfi = *reinterpret_cast(data); - - MetadataEntry entry; - FillEntryWithFiedldInfo(sfi, entry); - entry.isStatic = true; - entry.type = NodeType::StaticField; - entry.declaringType = ReadTypeName(sfi->declaringType); - - *data += sizeof(StaticFieldInfo); - - return entry; -} - -MetadataEntry MetadataReader::ReadInstanceMethodEntry(uint8_t** data) { - MetadataEntry entry; - MethodInfo mip(*data, this); //method info pointer+ - - FillEntryWithMethodInfo(mip, entry); - - *data += mip.GetSizeOfReadMethodInfo(); - - return entry; -} - -MetadataTreeNode* MetadataReader::GetNodeById(uint16_t nodeId) { +MetadataTreeNode *MetadataReader::GetNodeById(uint16_t nodeId) { return m_v[nodeId]; } -MetadataEntry MetadataReader::ReadStaticMethodEntry(uint8_t** data) { - MetadataEntry entry; - MethodInfo smip(*data, this); //static method info pointer - - FillEntryWithMethodInfo(smip, entry); - entry.isStatic = true; - entry.declaringType = smip.GetDeclaringType(); - - *data += smip.GetSizeOfReadMethodInfo(); - - return entry; -} - -MetadataEntry MetadataReader::ReadExtensionFunctionEntry(uint8_t** data) { - MetadataEntry entry; - MethodInfo smip(*data, this); //static method info pointer - - FillEntryWithMethodInfo(smip, entry); - entry.isStatic = true; - entry.declaringType = smip.GetDeclaringType(); - entry.isExtensionFunction = true; - - *data += smip.GetSizeOfReadMethodInfo(); - - return entry; -} - -string MetadataReader::ReadTypeName(MetadataTreeNode* treeNode) { +string MetadataReader::ReadTypeName(MetadataTreeNode *treeNode) { string name; auto itFound = m_typeNameCache.find(treeNode); @@ -178,13 +108,13 @@ string MetadataReader::ReadTypeName(MetadataTreeNode* treeNode) { } else { name = ReadTypeNameInternal(treeNode); - m_typeNameCache.insert(make_pair(treeNode, name)); + m_typeNameCache.emplace(treeNode, name); } return name; } -string MetadataReader::ReadTypeNameInternal(MetadataTreeNode* treeNode) { +string MetadataReader::ReadTypeNameInternal(MetadataTreeNode *treeNode) { string name; uint8_t prevNodeType; @@ -196,7 +126,7 @@ string MetadataReader::ReadTypeNameInternal(MetadataTreeNode* treeNode) { if (isArrayElement) { uint16_t forwardNodeId = treeNode->offsetValue - ARRAY_OFFSET; - MetadataTreeNode* forwardNode = GetNodeById(forwardNodeId); + MetadataTreeNode * forwardNode = GetNodeById(forwardNodeId); name = ReadTypeName(forwardNode); uint8_t forwardNodeType = GetNodeType(forwardNode); if (IsNodeTypeInterface(forwardNodeType) || IsNodeTypeClass(forwardNodeType)) { @@ -206,7 +136,7 @@ string MetadataReader::ReadTypeNameInternal(MetadataTreeNode* treeNode) { if (!name.empty()) { if (!IsNodeTypeArray(curNodeType)) { if ((IsNodeTypeClass(prevNodeType) || IsNodeTypeInterface(prevNodeType)) - && (IsNodeTypeClass(curNodeType) || IsNodeTypeInterface(curNodeType))) { + && (IsNodeTypeClass(curNodeType) || IsNodeTypeInterface(curNodeType))) { name = "$" + name; } else { name = "/" + name; @@ -225,11 +155,11 @@ string MetadataReader::ReadTypeNameInternal(MetadataTreeNode* treeNode) { return name; } -uint8_t* MetadataReader::GetValueData() const { +uint8_t *MetadataReader::GetValueData() const { return m_valueData; } -uint16_t MetadataReader::GetNodeId(MetadataTreeNode* treeNode) { +uint16_t MetadataReader::GetNodeId(MetadataTreeNode *treeNode) { auto itFound = find(m_v.begin(), m_v.end(), treeNode); assert(itFound != m_v.end()); uint16_t nodeId = itFound - m_v.begin(); @@ -237,11 +167,11 @@ uint16_t MetadataReader::GetNodeId(MetadataTreeNode* treeNode) { return nodeId; } -MetadataTreeNode* MetadataReader::GetRoot() const { +MetadataTreeNode *MetadataReader::GetRoot() const { return m_root; } -uint8_t MetadataReader::GetNodeType(MetadataTreeNode* treeNode) { +uint8_t MetadataReader::GetNodeType(MetadataTreeNode *treeNode) { if (treeNode->type == MetadataTreeNode::INVALID_TYPE) { uint8_t nodeType; @@ -255,7 +185,7 @@ uint8_t MetadataReader::GetNodeType(MetadataTreeNode* treeNode) { nodeType = MetadataTreeNode::ARRAY; } else { uint16_t nodeId = offsetValue - ARRAY_OFFSET; - MetadataTreeNode* arrElemNode = GetNodeById(nodeId); + MetadataTreeNode * arrElemNode = GetNodeById(nodeId); nodeType = *(m_valueData + arrElemNode->offsetValue); } @@ -265,19 +195,19 @@ uint8_t MetadataReader::GetNodeType(MetadataTreeNode* treeNode) { return treeNode->type; } -MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& className) { - MetadataTreeNode* treeNode = GetRoot(); +MetadataTreeNode *MetadataReader::GetOrCreateTreeNodeByName(const string &className) { + MetadataTreeNode * treeNode = GetRoot(); int arrayIdx = -1; string arrayName = "["; while (className[++arrayIdx] == '[') { - MetadataTreeNode* child = treeNode->GetChild(arrayName); + MetadataTreeNode * child = treeNode->GetChild(arrayName); if (child == nullptr) { - vector* children = treeNode->children; + vector *children = treeNode->children; if (children == nullptr) { - children = treeNode->children = new vector; + children = treeNode->children = new vector; } child = new MetadataTreeNode; @@ -301,19 +231,19 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN } } - vector < string > names; + vector names; Util::SplitString(cn, "/$", names); if (arrayIdx > 0) { bool found = false; - MetadataTreeNode* forwardedNode = GetOrCreateTreeNodeByName(cn); + MetadataTreeNode * forwardedNode = GetOrCreateTreeNodeByName(cn); uint16_t forwardedNodeId = GetNodeId(forwardedNode); if (treeNode->children == nullptr) { - treeNode->children = new vector(); + treeNode->children = new vector(); } - vector& children = *treeNode->children; - for (auto childNode : children) { + vector &children = *treeNode->children; + for (auto childNode: children) { uint32_t childNodeId = (childNode->offsetValue >= ARRAY_OFFSET) ? (childNode->offsetValue - ARRAY_OFFSET) : @@ -327,7 +257,7 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN } if (!found) { - MetadataTreeNode* forwardNode = new MetadataTreeNode; + MetadataTreeNode * forwardNode = new MetadataTreeNode; forwardNode->offsetValue = forwardedNodeId + ARRAY_OFFSET; forwardNode->parent = treeNode; @@ -342,15 +272,15 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN int curIdx = 0; for (auto it = names.begin(); it != names.end(); ++it) { - MetadataTreeNode* child = treeNode->GetChild(*it); + MetadataTreeNode * child = treeNode->GetChild(*it); if (child == nullptr) { - vector < string > api = m_getTypeMetadataCallback(cn, curIdx); + vector api = m_getTypeMetadataCallback(cn, curIdx); - for (const auto& part : api) { - vector* children = treeNode->children; + for (const auto &part: api) { + vector *children = treeNode->children; if (children == nullptr) { - children = treeNode->children = new vector; + children = treeNode->children = new vector; } child = new MetadataTreeNode; @@ -372,7 +302,8 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN if ((cKind == 'C') || (cKind == 'I')) { child->metadata = new string(part); - child->type = (cKind == 'C') ? MetadataTreeNode::CLASS : MetadataTreeNode::INTERFACE; + child->type = (cKind == 'C') ? MetadataTreeNode::CLASS + : MetadataTreeNode::INTERFACE; if (name == "S") { child->type |= MetadataTreeNode::STATIC; } @@ -388,7 +319,7 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN child->offsetValue = m_valueLength; m_valueData[m_valueLength++] = child->type; - *reinterpret_cast(m_valueData + m_valueLength) = baseClassNodeId; + *reinterpret_cast(m_valueData + m_valueLength) = baseClassNodeId; m_valueLength += sizeof(uint16_t); } else { child->type = MetadataTreeNode::PACKAGE; @@ -410,11 +341,12 @@ MetadataTreeNode* MetadataReader::GetOrCreateTreeNodeByName(const string& classN return treeNode; } -MetadataTreeNode* MetadataReader::GetBaseClassNode(MetadataTreeNode* treeNode) { - MetadataTreeNode* baseClassNode = nullptr; +MetadataTreeNode *MetadataReader::GetBaseClassNode(MetadataTreeNode *treeNode) { + MetadataTreeNode * baseClassNode = nullptr; if (treeNode != nullptr) { - uint16_t baseClassNodeId = *reinterpret_cast(m_valueData + treeNode->offsetValue + 1); + uint16_t baseClassNodeId = *reinterpret_cast(m_valueData + + treeNode->offsetValue + 1); size_t nodeCount = m_v.size(); diff --git a/test-app/runtime/src/main/cpp/MetadataReader.h b/test-app/runtime/src/main/cpp/MetadataReader.h index 284d1e952..c9f304589 100644 --- a/test-app/runtime/src/main/cpp/MetadataReader.h +++ b/test-app/runtime/src/main/cpp/MetadataReader.h @@ -6,78 +6,132 @@ #include #include #include -namespace tns { -typedef std::vector (*GetTypeMetadataCallback)(const std::string& classname, int index); +#include "robin_hood.h" -class MethodInfo; +namespace tns { + typedef std::vector (*GetTypeMetadataCallback)(const std::string &classname, + int index); -class MetadataReader { + class MetadataReader { public: MetadataReader(); - MetadataReader(uint32_t nodesLength, uint8_t* nodeData, uint32_t nameLength, uint8_t* nameData, uint32_t valueLength, uint8_t* valueData, GetTypeMetadataCallback getTypeMetadataCallack); + MetadataReader(uint32_t nodesLength, uint8_t *nodeData, uint32_t nameLength, + uint8_t *nameData, uint32_t valueLength, uint8_t *valueData, + GetTypeMetadataCallback getTypeMetadataCallack); + + inline static MetadataEntry ReadInstanceFieldEntry(uint8_t **data) { + MetadataEntry entry(nullptr, NodeType::Field); + entry.fi = *reinterpret_cast(data); + entry.isStatic = false; + entry.isTypeMember = false; + + *data += sizeof(FieldInfo); + + return entry; + } + + inline static MetadataEntry ReadStaticFieldEntry(uint8_t **data) { + MetadataEntry entry(nullptr, NodeType::StaticField); + entry.sfi = *reinterpret_cast(data); + entry.isStatic = true; + entry.isTypeMember = false; + + *data += sizeof(StaticFieldInfo); + + return entry; + } + + inline static MetadataEntry ReadInstanceMethodEntry(uint8_t **data) { + MetadataEntry entry(nullptr, NodeType::Method); + entry.isTypeMember = true; + + entry.mi = MethodInfo(*data); // Assign MethodInfo object directly + *data += entry.mi.GetSizeOfReadMethodInfo(); - MetadataEntry ReadInstanceMethodEntry(uint8_t** data); + return entry; + } + + inline static MetadataEntry ReadStaticMethodEntry(uint8_t **data) { + MetadataEntry entry(nullptr, NodeType::Method); + entry.isTypeMember = true; + + entry.mi = MethodInfo(*data); // Assign MethodInfo object directly + entry.mi.isStatic = true; + entry.isStatic = true; + + *data += entry.mi.GetSizeOfReadMethodInfo(); + + return entry; + } - MetadataEntry ReadStaticMethodEntry(uint8_t** data); + inline static MetadataEntry ReadExtensionFunctionEntry(uint8_t **data) { + MetadataEntry entry(nullptr, NodeType::Method); - MetadataEntry ReadExtensionFunctionEntry(uint8_t** data); + entry.mi = MethodInfo(*data); // Assign MethodInfo object directly + entry.mi.isStatic = true; + entry.isExtensionFunction = true; + entry.isStatic = true; - MetadataEntry ReadInstanceFieldEntry(uint8_t** data); + *data += entry.mi.GetSizeOfReadMethodInfo(); - MetadataEntry ReadStaticFieldEntry(uint8_t** data); + return entry; + } - inline std::string ReadTypeName(uint16_t nodeId){ - MetadataTreeNode* treeNode = GetNodeById(nodeId); + inline std::string ReadTypeName(uint16_t nodeId) { + MetadataTreeNode *treeNode = GetNodeById(nodeId); - return ReadTypeName(treeNode); - } + return ReadTypeName(treeNode); + } - std::string ReadTypeName(MetadataTreeNode* treeNode); + std::string ReadTypeName(MetadataTreeNode *treeNode); - inline std::string ReadName(uint32_t offset) { - uint16_t length = *reinterpret_cast(m_nameData + offset); + inline std::string ReadName(uint32_t offset) { + uint16_t length = *reinterpret_cast(m_nameData + offset); - std::string name(reinterpret_cast(m_nameData + offset + sizeof(uint16_t)), length); + std::string name(reinterpret_cast(m_nameData + offset + sizeof(uint16_t)), + length); - return name; - } + return name; + } - inline std::string ReadInterfaceImplementationTypeName(MetadataTreeNode* treeNode, bool& isPrefix) { - uint8_t* data = m_valueData + treeNode->offsetValue + sizeof(uint8_t) + sizeof(uint16_t); + inline std::string + ReadInterfaceImplementationTypeName(MetadataTreeNode *treeNode, bool &isPrefix) { + uint8_t *data = + m_valueData + treeNode->offsetValue + sizeof(uint8_t) + sizeof(uint16_t); - isPrefix = *data == 1; + isPrefix = *data == 1; - uint32_t pos = *reinterpret_cast(data + sizeof(uint8_t)); + uint32_t pos = *reinterpret_cast(data + sizeof(uint8_t)); - uint16_t len = *reinterpret_cast(m_nameData + pos); + uint16_t len = *reinterpret_cast(m_nameData + pos); - char* ptr = reinterpret_cast(m_nameData + pos + sizeof(uint16_t)); + char *ptr = reinterpret_cast(m_nameData + pos + sizeof(uint16_t)); - std::string name(ptr, len); + std::string name(ptr, len); - assert(name.length() == len); + assert(name.length() == len); - return name; - } + return name; + } - uint8_t* GetValueData() const; + uint8_t *GetValueData() const; - uint8_t GetNodeType(MetadataTreeNode* treeNode); + uint8_t GetNodeType(MetadataTreeNode *treeNode); - uint16_t GetNodeId(MetadataTreeNode* treeNode); + uint16_t GetNodeId(MetadataTreeNode *treeNode); - MetadataTreeNode* GetRoot() const; + MetadataTreeNode *GetRoot() const; - MetadataTreeNode* GetOrCreateTreeNodeByName(const std::string& className); + MetadataTreeNode *GetOrCreateTreeNodeByName(const std::string &className); - MetadataTreeNode* GetBaseClassNode(MetadataTreeNode* treeNode); + MetadataTreeNode *GetBaseClassNode(MetadataTreeNode *treeNode); - MetadataTreeNode* GetNodeById(uint16_t nodeId); + MetadataTreeNode *GetNodeById(uint16_t nodeId); inline bool IsNodeTypeArray(uint8_t type) { - bool isArray = (((type & MetadataTreeNode::PRIMITIVE) == 0) - && ((type & MetadataTreeNode::ARRAY) == MetadataTreeNode::ARRAY)); + bool isArray = (((type & MetadataTreeNode::PRIMITIVE) == 0) && + ((type & MetadataTreeNode::ARRAY) == MetadataTreeNode::ARRAY)); return isArray; } @@ -89,15 +143,16 @@ class MetadataReader { } inline bool IsNodeTypeClass(uint8_t type) { - bool isClass = (((type & MetadataTreeNode::PRIMITIVE) == 0) - && ((type & MetadataTreeNode::CLASS) == MetadataTreeNode::CLASS)); + bool isClass = (((type & MetadataTreeNode::PRIMITIVE) == 0) && + ((type & MetadataTreeNode::CLASS) == MetadataTreeNode::CLASS)); return isClass; } inline bool IsNodeTypeInterface(uint8_t type) { - bool isInterface = (((type & MetadataTreeNode::PRIMITIVE) == 0) - && ((type & MetadataTreeNode::INTERFACE) == MetadataTreeNode::INTERFACE)); + bool isInterface = (((type & MetadataTreeNode::PRIMITIVE) == 0) && + ((type & MetadataTreeNode::INTERFACE) == + MetadataTreeNode::INTERFACE)); return isInterface; } @@ -108,18 +163,13 @@ class MetadataReader { return isPackage; } - inline static void FillReturnType(MetadataEntry& entry) { - entry.returnType = ParseReturnType(entry.sig); - entry.retType = GetReturnType(entry.returnType); - } - - inline static std::string ParseReturnType(const std::string& signature) { + inline static std::string ParseReturnType(const std::string &signature) { int idx = signature.find(')'); auto returnType = signature.substr(idx + 1); return returnType; } - inline static MethodReturnType GetReturnType(const std::string& returnType) { + inline static MethodReturnType GetReturnType(const std::string &returnType) { MethodReturnType retType; char retTypePrefix = returnType[0]; switch (retTypePrefix) { @@ -154,8 +204,7 @@ class MetadataReader { case 'L': retType = (returnType == "Ljava/lang/String;") ? MethodReturnType::String - : - MethodReturnType::Object; + : MethodReturnType::Object; break; default: assert(false); @@ -166,28 +215,28 @@ class MetadataReader { private: - static const uint32_t ARRAY_OFFSET = 1000000000; + static const uint32_t ARRAY_OFFSET = INT32_MAX; // 2147483647 - MetadataTreeNode* BuildTree(); + MetadataTreeNode *BuildTree(); - std::string ReadTypeNameInternal(MetadataTreeNode* treeNode); + std::string ReadTypeNameInternal(MetadataTreeNode *treeNode); - void FillEntryWithFiedldInfo(FieldInfo* fi, MetadataEntry& entry); + void FillEntryWithFiedldInfo(FieldInfo *fi, MetadataEntry &entry); - void FillEntryWithMethodInfo(MethodInfo& mi, MetadataEntry& entry); + void FillEntryWithMethodInfo(MethodInfo &mi, MetadataEntry &entry); - MetadataTreeNode* m_root; + MetadataTreeNode *m_root; uint32_t m_nodesLength; uint32_t m_nameLength; uint32_t m_valueLength; - uint8_t* m_nodeData; - uint8_t* m_nameData; - uint8_t* m_valueData; - std::vector m_v; + uint8_t *m_nodeData; + uint8_t *m_nameData; + uint8_t *m_valueData; + std::vector m_v; GetTypeMetadataCallback m_getTypeMetadataCallback; - std::map m_typeNameCache; -}; + robin_hood::unordered_map m_typeNameCache; + }; } #endif /* METADATAREADER_H_ */ diff --git a/test-app/runtime/src/main/cpp/MethodCache.cpp b/test-app/runtime/src/main/cpp/MethodCache.cpp index 8e2f2a9d4..587933728 100644 --- a/test-app/runtime/src/main/cpp/MethodCache.cpp +++ b/test-app/runtime/src/main/cpp/MethodCache.cpp @@ -54,7 +54,7 @@ MethodCache::CacheMethodInfo MethodCache::ResolveMethodSignature(const string& c : env.GetMethodID(clazz, methodName, signature); - s_mthod_ctor_signature_cache.insert(make_pair(encoded_method_signature, method_info)); + s_mthod_ctor_signature_cache.emplace(encoded_method_signature, method_info); } } else { method_info = (*it).second; @@ -81,7 +81,7 @@ MethodCache::CacheMethodInfo MethodCache::ResolveConstructorSignature(const Args constructor_info.signature = signature; constructor_info.mid = env.GetMethodID(javaClass, "", signature); - s_mthod_ctor_signature_cache.insert(make_pair(encoded_ctor_signature, constructor_info)); + s_mthod_ctor_signature_cache.emplace(encoded_ctor_signature, constructor_info); } } else { constructor_info = (*it).second; @@ -261,7 +261,7 @@ string MethodCache::ResolveConstructor(const FunctionCallbackInfo& args, return resolvedSignature; } -map MethodCache::s_mthod_ctor_signature_cache; +robin_hood::unordered_map MethodCache::s_mthod_ctor_signature_cache; jclass MethodCache::RUNTIME_CLASS = nullptr; jmethodID MethodCache::RESOLVE_METHOD_OVERLOAD_METHOD_ID = nullptr; jmethodID MethodCache::RESOLVE_CONSTRUCTOR_SIGNATURE_ID = nullptr; diff --git a/test-app/runtime/src/main/cpp/MethodCache.h b/test-app/runtime/src/main/cpp/MethodCache.h index a37acaf10..b253d2b37 100644 --- a/test-app/runtime/src/main/cpp/MethodCache.h +++ b/test-app/runtime/src/main/cpp/MethodCache.h @@ -59,7 +59,7 @@ class MethodCache { * Used for caching the resolved constructor or method signature. * The encoded signature has template: .S/I....<...> */ - static std::map s_mthod_ctor_signature_cache; + static robin_hood::unordered_map s_mthod_ctor_signature_cache; }; } diff --git a/test-app/runtime/src/main/cpp/ModuleBinding.cpp b/test-app/runtime/src/main/cpp/ModuleBinding.cpp new file mode 100644 index 000000000..5050ff1d5 --- /dev/null +++ b/test-app/runtime/src/main/cpp/ModuleBinding.cpp @@ -0,0 +1,101 @@ +// +// ModuleBinding.cpp +// NativeScript +// +// Created by Eduardo Speroni on 5/11/23. +// Copyright © 2023 Progress. All rights reserved. +// + +#include "ModuleBinding.h" + +// TODO: add here +//#define NSC_BUILTIN_STANDARD_BINDINGS(V) \ +//V(fs) + +#define NSC_BUILTIN_STANDARD_BINDINGS(V) + + +#define NSC_BUILTIN_BINDINGS(V) \ +NSC_BUILTIN_STANDARD_BINDINGS(V) + +// This is used to load built-in bindings. Instead of using +// __attribute__((constructor)), we call the _register_ +// function for each built-in bindings explicitly in +// binding::RegisterBuiltinBindings(). This is only forward declaration. +// The definitions are in each binding's implementation when calling +// the NODE_BINDING_CONTEXT_AWARE_INTERNAL. +#define V(modname) void _register_##modname(); +NSC_BUILTIN_BINDINGS(V) +#undef V + + + + +#define V(modname) \ + void _register_isolate_##modname(v8::Isolate* isolate, \ + v8::Local target); +NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) +#undef V + + + +using v8::Context; +using v8::EscapableHandleScope; +using v8::Exception; +using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; +using v8::HandleScope; +using v8::Isolate; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Value; + +namespace tns { +// Globals per process +static ns_module* modlist_internal; +static ns_module* modlist_linked; +static thread_local ns_module* thread_local_modpending; +bool node_is_initialized = false; + +extern "C" void nativescript_module_register(void* m) { + struct ns_module* mp = reinterpret_cast(m); + + if (mp->nm_flags & NM_F_INTERNAL) { + mp->nm_link = modlist_internal; + modlist_internal = mp; + } else if (!node_is_initialized) { + // "Linked" modules are included as part of the node project. + // Like builtins they are registered *before* node::Init runs. + mp->nm_flags = NM_F_LINKED; + mp->nm_link = modlist_linked; + modlist_linked = mp; + } else { + thread_local_modpending = mp; + } +} + +namespace binding { + +void RegisterBuiltinBindings() { +#define V(modname) _register_##modname(); + NSC_BUILTIN_BINDINGS(V) +#undef V +} + +void CreateInternalBindingTemplates(v8::Isolate* isolate, Local templ) { +#define V(modname) \ + do { \ + /*templ->InstanceTemplate()->SetInternalFieldCount( \ + BaseObject::kInternalFieldCount);*/ \ + _register_isolate_##modname(isolate, templ); \ + /*isolate_data->set_##modname##_binding(templ);*/ \ + } while (0); + NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) +#undef V +} + +}; + +}; + diff --git a/test-app/runtime/src/main/cpp/ModuleBinding.h b/test-app/runtime/src/main/cpp/ModuleBinding.h new file mode 100644 index 000000000..258b8d9bf --- /dev/null +++ b/test-app/runtime/src/main/cpp/ModuleBinding.h @@ -0,0 +1,98 @@ +// +// ModuleBinding.hpp +// NativeScript +// +// Created by Eduardo Speroni on 5/11/23. +// Copyright © 2023 Progress. All rights reserved. +// + +#ifndef ModuleBinding_hpp +#define ModuleBinding_hpp + +#include "v8.h" + + +namespace tns { + +#define NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \ + static tns::ns_module _module = { \ + NODE_MODULE_VERSION, \ + flags, \ + nullptr, \ + __FILE__, \ + nullptr, \ + (tns::addon_context_register_func)(regfunc), \ + NODE_STRINGIFY(modname), \ + priv, \ + nullptr}; \ + void _register_##modname() { node_module_register(&_module); } + +#define NODE_BINDING_CONTEXT_AWARE_INTERNAL(modname, regfunc) \ + NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL) + + + + + + + + +#define NODE_BINDING_PER_ISOLATE_INIT(modname, per_isolate_func) \ + void _register_isolate_##modname(v8::Isolate* isolate, \ + v8::Local target) { \ + per_isolate_func(isolate, target); \ + } + + +// This is a helepr that gives the target as an ObjectTemplate (using target.PrototypeTemplate()) + +#define NODE_BINDING_PER_ISOLATE_INIT_OBJ(modname, per_isolate_func) \ + void _register_isolate_##modname(v8::Isolate* isolate, \ + v8::Local target) { \ + per_isolate_func(isolate, target->PrototypeTemplate()); \ + } + + +#define NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) \ +V(timers) + +enum { + NM_F_BUILTIN = 1 << 0, // Unused. + NM_F_LINKED = 1 << 1, + NM_F_INTERNAL = 1 << 2, + NM_F_DELETEME = 1 << 3, +}; + +typedef void (*addon_register_func)( + v8::Local exports, + v8::Local module, + void* priv); + +typedef void (*addon_context_register_func)( + v8::Local exports, + v8::Local module, + v8::Local context, + void* priv); + +struct ns_module { + int nm_version; + unsigned int nm_flags; + void* nm_dso_handle; + const char* nm_filename; + tns::addon_register_func nm_register_func; + tns::addon_context_register_func nm_context_register_func; + const char* nm_modname; + void* nm_priv; + struct ns_module* nm_link; +}; + +namespace binding { +void RegisterBuiltinBindings(); +void CreateInternalBindingTemplates(v8::Isolate* isolate, v8::Local templ); +}; + + +}; + + +#endif /* ModuleBinding_hpp */ diff --git a/test-app/runtime/src/main/cpp/ModuleInternal.cpp b/test-app/runtime/src/main/cpp/ModuleInternal.cpp index e61be0273..a7779cc50 100644 --- a/test-app/runtime/src/main/cpp/ModuleInternal.cpp +++ b/test-app/runtime/src/main/cpp/ModuleInternal.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include using namespace v8; using namespace std; @@ -132,7 +134,7 @@ Local ModuleInternal::GetRequireFunction(Isolate* isolate, const strin auto poFunc = new Persistent(isolate, requireFunc); - m_requireCache.insert(make_pair(dirName, poFunc)); + m_requireCache.emplace(dirName, poFunc); } return requireFunc; @@ -446,7 +448,7 @@ Local ModuleInternal::LoadData(Isolate* isolate, const string& path) { auto poObj = new Persistent(isolate, json); - m_loadedModules.insert(make_pair(path, ModuleCacheEntry(poObj, true /* isData */))); + m_loadedModules.emplace(path, ModuleCacheEntry(poObj, true /* isData */)); return json; } @@ -478,8 +480,9 @@ ScriptCompiler::CachedData* ModuleInternal::TryLoadScriptCache(const std::string auto cacheLastModifiedTime = result.st_mtime; if (stat(path.c_str(), &result) == 0) { auto jsLastModifiedTime = result.st_mtime; - if (jsLastModifiedTime > 0 && cacheLastModifiedTime > 0 && jsLastModifiedTime > cacheLastModifiedTime) { - // The javascript file is more recent than the cache file => ignore the cache + if (jsLastModifiedTime != cacheLastModifiedTime) { + // files have different dates, ignore the cache file (this is enforced by the + // SaveScriptCache function) return nullptr; } } @@ -508,6 +511,16 @@ void ModuleInternal::SaveScriptCache(const Local