Compare commits

..

10 commits

Author SHA1 Message Date
Zoltan Herczeg
6740732ca8 [return-check] Change throws to returns
Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
2023-11-09 17:14:12 +09:00
HyukWoo Park
a41d6c5ff5 Add web-tooling-benchmark
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-10-18 11:24:37 +09:00
HyukWoo Park
0197d3215b Disable unsupported debugger keyword message
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-10-18 11:19:31 +09:00
HyukWoo Park
14089804d5 Fix remaining exception handlings
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-09-01 14:11:02 +09:00
HyukWoo Park
a65e699415 Update README
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 20:52:19 +09:00
HyukWoo Park
657ea2da18 Fix missing exception handling in API to run sunspider benchmark
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 20:23:34 +09:00
HyukWoo Park
3f8ce198c9 Remove trivial try-catch statements
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 19:24:13 +09:00
HyukWoo Park
30ae0db273 Disable intl modules in default
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 18:36:58 +09:00
HyukWoo Park
26af0cddc6 [return-check] change exception handling to return-check based method in interpreting (runtime) process
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 18:36:46 +09:00
HyukWoo Park
da24cd6a2f [return-check] change exception handling to return-check based method in parsing process
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
2023-08-18 18:36:15 +09:00
505 changed files with 44808 additions and 228105 deletions

View file

@ -4,23 +4,24 @@ on:
schedule:
# trigger on every monday, wednesday and friday
- cron: '30 22 * * 1,3,5'
workflow_dispatch:
jobs:
coverity-scan:
if: github.repository == 'Samsung/escargot'
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ICU(64)
submodules: true
- name: Install Packages
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu64-build/
cd $GITHUB_WORKSPACE/icu64-build/icu4c/source
LDFLAGS="-Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib/" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu64/"
make -j8
make install
sudo apt-get update
sudo apt-get install -y ninja-build
- name: Patch WABT
working-directory: ./third_party/wasm/wabt
run: |
cp ../../../tools/test/wasm-js/wabt_patch .
patch -p0 < wabt_patch
- name: Download Coverity Tool
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
@ -30,10 +31,10 @@ jobs:
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
- name: Build
env:
BUILD_OPTIONS: -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_CODE_CACHE=ON -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_CODE_CACHE=ON -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
export PATH=$GITHUB_WORKSPACE/cov-analysis-linux64/bin:$PATH
LDFLAGS="-L$GITHUB_WORKSPACE/icu64/lib/ -Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib/" PKG_CONFIG_PATH="$GITHUB_WORKSPACE/icu64/lib/pkgconfig/" cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/coverity_scan $BUILD_OPTIONS
cmake -H. -Bout/coverity_scan $BUILD_OPTIONS
cov-build --dir cov-int ninja -Cout/coverity_scan
- name: Submit
env:
@ -45,26 +46,28 @@ jobs:
--form token=$TOKEN \
--form email=$NOTI_MAIL \
--form file=@escargot.tgz \
--form version="4.3.0" \
--form version="4.0.0" \
--form description="escargot coverity scan" \
https://scan.coverity.com/builds?project=Samsung%2Fescargot
coverage-scan:
if: github.repository == 'Samsung/escargot'
runs-on: [self-hosted, linux, x64, test]
timeout-minutes: 600
# ubuntu version fixed
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
sudo apt-get update
sudo apt-get install -y pypy ninja-build libicu-dev gcovr
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_COVERAGE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_COVERAGE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
LDFLAGS=" -L/usr/icu78-64/lib/ -Wl,-rpath=/usr/icu78-64/lib/" PKG_CONFIG_PATH="/usr/icu78-64/lib/pkgconfig/" cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/coverage64 -DESCARGOT_ARCH=x64 $BUILD_OPTIONS
ninja -Cout/coverage64
LDFLAGS=" -L/usr/icu78-32/lib/ -Wl,-rpath=/usr/icu78-32/lib/" PKG_CONFIG_PATH="/usr/icu78-32/lib/pkgconfig/" cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/coverage32 -DESCARGOT_ARCH=x86 $BUILD_OPTIONS
ninja -Cout/coverage32
cmake -H. -Bout/coverage $BUILD_OPTIONS
ninja -Cout/coverage
- name: Run test262 and collect coverage data
# test262 is unstable in actions env, but coverage data will be accumulated
continue-on-error: true
@ -73,13 +76,12 @@ jobs:
sudo locale-gen en_US.UTF-8
export LANG=en_US.UTF-8
locale
LD_LIBRARY_PATH=/usr/icu78-64/lib/ GC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/coverage64/escargot" new-es regression-tests test262 octane chakracore sunspider-js modifiedVendorTest jsc-stress v8 spidermonkey intl jetstream-only-cdjs
LD_LIBRARY_PATH=/usr/icu78-32/lib/ GC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --arch=x86 --engine="$GITHUB_WORKSPACE/out/coverage32/escargot" new-es regression-tests test262 octane chakracore sunspider-js modifiedVendorTest jsc-stress v8 spidermonkey intl jetstream-only-cdjs
tools/run-tests.py --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/coverage/escargot" new-es test262
- name: Generate coverage report
run: |
gcovr --gcov-ignore-parse-errors --exclude-unreachable-branches --exclude-throw-branches --exclude '.*third_party/' --exclude '.*shell/' --exclude '.*api/' -r . --xml coverage.xml
gcovr --gcov-ignore-parse-errors --exclude-unreachable-branches --exclude-throw-branches --exclude third_party --exclude src/api -r . --xml coverage.xml
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true

View file

@ -1,97 +0,0 @@
name: Android-Release
on:
push:
tags:
- "v*.*.*"
jobs:
build-android-on-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up JDK
uses: actions/setup-java@v4.1.0
with:
distribution: "zulu"
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Build with Gradle
working-directory: ./build/android
run: |
./gradlew bundleHostJar
./gradlew javadocJar
./gradlew sourcesJar
./gradlew :escargot:testDebugUnitTest
mv ./escargot/build/libs/escargot.jar ./escargot/build/libs/escargot-ubuntu.jar
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build-artifact-ubuntu
path: |
./build/android/escargot/build/**/escargot-*.aar
./build/android/escargot/build/**/escargot-*.jar
!./build/android/escargot/build/**/escargot-*Shell.aar
if-no-files-found: error
build-android-on-macos:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install Packages
run: |
brew update
brew install ninja icu4c
- name: Set up JDK
uses: actions/setup-java@v4.1.0
with:
distribution: "zulu"
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Build with Gradle
working-directory: ./build/android
run: |
./gradlew bundleHostJar
./gradlew :escargot:testDebugUnitTest
mv ./escargot/build/libs/escargot.jar ./escargot/build/libs/escargot-mac.jar
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build-artifact-mac
path: |
./build/android/escargot/build/libs/escargot-mac.jar
if-no-files-found: error
merge-update-release:
needs: [build-android-on-ubuntu, build-android-on-macos]
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-artifact-*
merge-multiple: true
- name: Set release date
run: |
echo "RELEASE_DATE=$(date --rfc-3339=date)" >> $GITHUB_ENV
- name: Merge build artifacts
working-directory: ./artifacts
run: |
ls -R ./
echo ${RELEASE_DATE}
find . -type f -name "escargot-*.aar" -exec mv {} . \;
find . -type f -name "escargot-*.jar" -exec mv {} . \;
ls -R ./
find ./ -type f -name "escargot-*.aar" -o -name "escargot-*.jar" | zip Android-Release-${{ env.RELEASE_DATE }}.zip -@
- name: Upload to release
uses: softprops/action-gh-release@v2
with:
files: |
artifacts/Android-Release-${{ env.RELEASE_DATE }}.zip

View file

@ -1,110 +0,0 @@
name: Review Bot (PR)
on:
pull_request_target:
types: [opened, synchronize, reopened]
branches: [ "master" ]
concurrency:
group: review-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
review:
if: github.repository == 'Samsung/escargot'
runs-on: [self-hosted, escargot-review]
steps:
- name: Compute diff range (incremental on synchronize)
id: shas
uses: actions/github-script@v7
with:
script: |
const action = context.payload.action;
const pr = context.payload.pull_request.number;
const baseSha = context.payload.pull_request.base.sha;
const headSha = context.payload.pull_request.head.sha;
let base = baseSha;
let skip = false;
if (action === 'synchronize') {
const before = context.payload.before;
if (before) {
base = before;
} else {
skip = true;
}
}
core.setOutput('base', base);
core.setOutput('head', headSha);
core.setOutput('pr', pr);
core.setOutput('skip', String(skip));
- name: Skip review (no before on synchronize)
if: ${{ steps.shas.outputs.skip == 'true' }}
run: |
echo "[Review Bot] Skipping review: 'before' SHA missing on synchronize event."
- name: Call review server
id: call
if: ${{ steps.shas.outputs.skip != 'true' }}
env:
REVIEW_SERVER: ${{ secrets.REVIEW_SERVER }}
run: |
set -euo pipefail
REVIEW_SERVER="${REVIEW_SERVER}"
BASE_SHA="${{ steps.shas.outputs.base }}"
HEAD_SHA="${{ steps.shas.outputs.head }}"
PR_NUMBER="${{ steps.shas.outputs.pr }}"
curl -sS --fail-with-body --show-error \
--connect-timeout 10 --max-time 7200 \
-X POST "${REVIEW_SERVER}/review" \
-H "Content-Type: application/json" \
-d "{\"base_sha\":\"${BASE_SHA}\",\"head_sha\":\"${HEAD_SHA}\",\"pull_request_number\":${PR_NUMBER}}" \
-o review.json
echo "==== review.json ===="
cat review.json
- name: Post review comments
if: ${{ steps.shas.outputs.skip != 'true' }}
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const pr = context.payload.pull_request.number;
let raw;
try {
raw = fs.readFileSync('review.json', 'utf8');
} catch (e) {
core.warning(`review.json not found: ${e}`);
return;
}
let data;
try {
data = JSON.parse(raw);
} catch (e) {
core.warning(`Failed to parse review.json as JSON: ${e}`);
return;
}
const comments = Array.isArray(data.comments) ? data.comments : [];
for (const c of comments) {
await github.request('POST /repos/{owner}/{repo}/pulls/{pull_number}/comments', {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr,
body: c.body,
commit_id: c.commit_id,
path: c.path,
line: c.line,
side: c.side,
headers: { 'accept': 'application/vnd.github+json' }
});
await new Promise(r => setTimeout(r, 200));
}

View file

@ -5,126 +5,121 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
env:
RUNNER: tools/run-tests.py
jobs:
check-tidy:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo add-apt-repository "deb [trusted=yes] http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main"
sudo add-apt-repository "deb http://mirrors.kernel.org/ubuntu/ focal main universe"
sudo apt-get update
sudo apt-get install -y clang-format-20
sudo apt-get install -y clang-format-6.0
- name: Test
run: tools/check_tidy.py
build-on-macos:
runs-on: macos-15
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: recursive
submodules: true
- name: Install Packages
run: |
brew update
brew install ninja icu4c
brew install cmake ninja pkg-config icu4c
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
# check cpu
sysctl -a | grep machdep.cpu
# add icu path to pkg_config_path
export PKG_CONFIG_PATH="$(brew --prefix icu4c)/lib/pkgconfig"
echo $PKG_CONFIG_PATH
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -H. -Bout/debug/ -DESCARGOT_MODE=debug $BUILD_OPTIONS
ninja -Cout/debug/
$RUNNER --engine="./out/debug/escargot" new-es
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -H. -Bout/release/ -DESCARGOT_MODE=release $BUILD_OPTIONS
ninja -Cout/release/
cp test/octane/*.js .
./out/release/escargot run.js
build-on-macos-arm64:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Packages
run: |
brew update
brew install ninja icu4c
- name: Build arm64
env:
BUILD_OPTIONS: -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
# check cpu
sysctl -a | grep machdep.cpu
# add icu path to pkg_config_path
export PKG_CONFIG_PATH="$(brew --prefix icu4c)/lib/pkgconfig"
echo $PKG_CONFIG_PATH
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -H. -Bout/debug/ -DESCARGOT_MODE=debug $BUILD_OPTIONS
ninja -Cout/debug/
$RUNNER --engine="./out/debug/escargot" new-es
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -H. -Bout/release/ -DESCARGOT_MODE=release $BUILD_OPTIONS
ninja -Cout/release/
cp test/octane/*.js .
./out/release/escargot run.js
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"
cmake -H. -Bout/mac/x64 $BUILD_OPTIONS
ninja -Cout/mac/x64
./tools/run-tests.py --engine="./out/mac/x64/escargot" new-es
build-test-on-android:
runs-on: ubuntu-latest
runs-on: macos-12
strategy:
matrix:
arch: [x86, x86_64]
api: [28]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Enable KVM
- name: Install Packages
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
brew update
brew install cmake pkg-config
- name: Set up JDK
uses: actions/setup-java@v4.1.0
uses: actions/setup-java@v3
with:
distribution: "zulu"
java-version: 17
- name: Gradle cache
uses: gradle/actions/setup-gradle@v3
- name: Create AVD and run tests
uses: gradle/gradle-build-action@v2
- name: AVD cache
uses: actions/cache@v3
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ matrix.api }}-${{ matrix.arch }}
- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api }}
arch: ${{ matrix.arch }}
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -camera-back none -no-snapshot-save -gpu swiftshader_indirect -noaudio -no-boot-anim
disable-animations: true
script: cd build/android/;./gradlew connectedDebugAndroidTest -DESCARGOT_BUILD_TLS_ACCESS_BY_PTHREAD_KEY=ON
build-test-tizen:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: echo "Generated AVD snapshot for caching."
- name: Run tests
uses: reactivecircus/android-emulator-runner@v2
with:
submodules: recursive
- name: prepare deb sources for GBS
run: echo "deb [trusted=yes] http://download.tizen.org/tools/latest-release/Ubuntu_24.04/ /" | sudo tee /etc/apt/sources.list.d/tizen.list
- name: install GBS
run: sudo apt-get update && sudo apt-get install -y gbs
- name: build
api-level: ${{ matrix.api }}
arch: ${{ matrix.arch }}
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: cd build/android/;./gradlew connectedDebugAndroidTest
build-by-clang:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
gbs -c .github/workflows/gbs.conf build -A armv7l -P profile.tizen --incremental --define "enable_shell 1"
sudo apt-get update
sudo apt-get install -y ninja-build gcc-multilib g++-multilib libicu-dev
- name: Patch WABT
working-directory: ./third_party/wasm/wabt
run: |
cp ../../../tools/test/wasm-js/wabt_patch .
patch -p0 < wabt_patch
- name: Build x86
env:
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
CC=clang CXX=clang++ cmake -H. -Bout/clang/x86 $BUILD_OPTIONS
ninja -Cout/clang/x86
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
CC=clang CXX=clang++ cmake -H. -Bout/clang/x64 $BUILD_OPTIONS
ninja -Cout/clang/x64
./tools/run-tests.py --engine="./out/clang/x64/escargot" new-es
test-on-windows-clang-cl:
runs-on: windows-2022
@ -132,61 +127,39 @@ jobs:
matrix:
# clang-cl with cannot generate c++ exception code well
# if clang-cl bug fixed, we can add x64
# clang version and STL version are sometimes not matched in github actions,
# so I add -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH
arch: [
{cpu: "x86", flag: "-m32 -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"}
#, {cpu: "x64", flag: "-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"}
{cpu: "x86", flag: "-m32"}
# , {cpu: "x64", flag: ""}
]
steps:
- name: Set git cllf config
run: |
git config --global core.autocrlf input
git config --global core.eol lf
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- uses: szenius/set-timezone@v2.0
- uses: szenius/set-timezone@v1.2
with:
timezoneWindows: "Pacific Standard Time"
- uses: lukka/get-cmake@latest
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11
with:
cmakeVersion: "~3.25.0"
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
with:
sdk-version: 26100
- uses: actions/setup-python@v5
sdk-version: 20348
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Download and Install Visual C++ Redistributable
shell: powershell
- name: Install msvc redist package
run: |
$vcRedistUrl64 = "https://aka.ms/vs/17/release/vc_redist.x64.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath64 = "$env:TEMP\vc_redist.x64.exe"
$vcRedistUrl32 = "https://aka.ms/vs/17/release/vc_redist.x86.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath32 = "$env:TEMP\vc_redist.x86.exe"
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl64"
Invoke-WebRequest -Uri $vcRedistUrl64 -OutFile $vcRedistPath64
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl32"
Invoke-WebRequest -Uri $vcRedistUrl32 -OutFile $vcRedistPath32
Write-Host "Installing Visual C++ Redistributable silently"
Start-Process -FilePath $vcRedistPath64 -ArgumentList "/install /quiet /norestart" -Wait
Start-Process -FilePath $vcRedistPath32 -ArgumentList "/install /quiet /norestart" -Wait
Write-Host "Visual C++ Redistributable installation complete."
- uses: ilammy/msvc-dev-cmd@v1.13.0
(new-object System.Net.WebClient).DownloadFile('https://github.com/abbodi1406/vcredist/releases/download/v0.73.0/VisualCppRedist_AIO_x86_x64.exe','VisualCppRedist_AIO_x86_x64.exe')
.\VisualCppRedist_AIO_x86_x64.exe /y
- uses: ilammy/msvc-dev-cmd@v1.12.1
with:
arch: ${{ matrix.arch.cpu }}
sdk: "10.0.26100.0"
- uses: egor-tensin/setup-clang@v1
with:
version: 19.1.7
platform: ${{ matrix.arch.cpu }}
sdk: "10.0.20348.0"
- name: Build ${{ matrix.arch.cpu }} Release
run: |
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch.cpu }} -Bout/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -G Ninja -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=release -DCMAKE_C_FLAGS="${{ matrix.arch.flag }}" -DCMAKE_CXX_FLAGS="${{ matrix.arch.flag }}"
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch.cpu }} -Bout/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=NO -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -G Ninja -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=release -DCMAKE_C_FLAGS="${{ matrix.arch.flag }}" -DCMAKE_CXX_FLAGS="${{ matrix.arch.flag }}"
CMake --build out/ --config Release
- name: Run octane
run: |
@ -196,9 +169,9 @@ jobs:
# clang-cl with cannot generate c++ exception code well. if clang-cl bug fixed, we can enable test262
# - name: Run test262
# run: |
# set GC_FREE_SPACE_DIVISOR=1
# pip install chardet
# python tools\run-tests.py --engine=%cd%\out\escargot.exe test262 --test262-extra-arg="--skip Temporal --skip intl402 --skip Atomics"
# set GC_FREE_SPACE_DIVISOR=1
# pip install chardet
# python tools\run-tests.py --engine=%cd%\out\escargot.exe test262 --extra-arg="--skip Temporal --skip intl402 --skip Atomics"
# shell: cmd
- if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
@ -214,46 +187,30 @@ jobs:
run: |
git config --global core.autocrlf input
git config --global core.eol lf
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: szenius/set-timezone@v2.0
submodules: true
- uses: szenius/set-timezone@v1.2
with:
timezoneWindows: "Pacific Standard Time"
- uses: lukka/get-cmake@latest
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
with:
sdk-version: 26100
- uses: actions/setup-python@v5
sdk-version: 20348
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Download and Install Visual C++ Redistributable
shell: powershell
- name: Install msvc redist package
run: |
$vcRedistUrl64 = "https://aka.ms/vs/17/release/vc_redist.x64.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath64 = "$env:TEMP\vc_redist.x64.exe"
$vcRedistUrl32 = "https://aka.ms/vs/17/release/vc_redist.x86.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath32 = "$env:TEMP\vc_redist.x86.exe"
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl64"
Invoke-WebRequest -Uri $vcRedistUrl64 -OutFile $vcRedistPath64
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl32"
Invoke-WebRequest -Uri $vcRedistUrl32 -OutFile $vcRedistPath32
Write-Host "Installing Visual C++ Redistributable silently"
Start-Process -FilePath $vcRedistPath64 -ArgumentList "/install /quiet /norestart" -Wait
Start-Process -FilePath $vcRedistPath32 -ArgumentList "/install /quiet /norestart" -Wait
Write-Host "Visual C++ Redistributable installation complete."
- uses: ilammy/msvc-dev-cmd@v1.13.0
(new-object System.Net.WebClient).DownloadFile('https://github.com/abbodi1406/vcredist/releases/download/v0.73.0/VisualCppRedist_AIO_x86_x64.exe','VisualCppRedist_AIO_x86_x64.exe')
.\VisualCppRedist_AIO_x86_x64.exe /y
- uses: ilammy/msvc-dev-cmd@v1.12.1
with:
arch: ${{ matrix.arch }}
sdk: "10.0.26100.0"
sdk: "10.0.20348.0"
- name: Build ${{ matrix.arch }} Release
run: |
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -DESCARGOT_ARCH=${{ matrix.arch }} -Bout/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_WASM=ON -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=release
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -DESCARGOT_ARCH=${{ matrix.arch }} -Bout/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=release
CMake --build out/ --config Release
# windows internal ICU doesn't support Temporal and intl402 well
# github action windows runner only have 2 CPUs. that's why I disable Atomics(timeout occured with some tests)
@ -261,7 +218,7 @@ jobs:
run: |
set GC_FREE_SPACE_DIVISOR=1
pip install chardet
python tools\run-tests.py --engine=%cd%\out\escargot.exe test262 --test262-extra-arg="--skip Temporal --skip intl402 --skip Atomics --skip sm"
python tools\run-tests.py --engine=%cd%\out\escargot.exe test262 --extra-arg="--skip Temporal --skip intl402 --skip Atomics"
shell: cmd
- name: Run octane
run: |
@ -279,32 +236,30 @@ jobs:
run: |
git config --global core.autocrlf input
git config --global core.eol lf
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- uses: lukka/get-cmake@latest
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
with:
sdk-version: 26100
- uses: ilammy/msvc-dev-cmd@v1.13.0
sdk-version: 20348
- uses: ilammy/msvc-dev-cmd@v1.12.1
with:
arch: x64
sdk: "10.0.26100.0"
sdk: "10.0.20348.0"
uwp: true
- name: Build x64 UWP Release
run: |
CMake -G "Visual Studio 17 2022" -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=x64 -Bout/win64_release_uwp/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON
CMake --build out\win64_release_uwp --config Release
CMake -G "Visual Studio 17 2022" -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=x64 -Bout/win64_release_uwp/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_TEST=ON
cmake --build out\win64_release_uwp --config Release
shell: cmd
- uses: ilammy/msvc-dev-cmd@v1.13.0
- uses: ilammy/msvc-dev-cmd@v1.12.1
with:
arch: x86
sdk: "10.0.26100.0"
sdk: "10.0.20348.0"
- name: Build x86 DLL Release
run: |
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=x86 -Bout/win32_release_shared/ -DESCARGOT_OUTPUT=shared_lib -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=release
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=x86 -Bout/win32_release_shared/ -DESCARGOT_OUTPUT=shared_lib -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=release
CMake --build out/win32_release_shared --config Release
shell: cmd
- if: ${{ failure() }}
@ -312,254 +267,112 @@ jobs:
timeout-minutes: 15
build-test-on-x86-release:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
strategy:
matrix:
tc: ['new-es octane', 'v8 chakracore spidermonkey', 'jetstream-only-simple-parallel-1', 'jetstream-only-simple-parallel-2 jsc-stress', 'jetstream-only-simple-parallel-3 jetstream-only-cdjs']
tc: ['octane', 'v8 chakracore spidermonkey', 'jetstream-only-simple-parallel-1', 'jetstream-only-simple-parallel-2 jsc-stress', 'jetstream-only-simple-parallel-3 jetstream-only-cdjs']
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
sudo apt-get update
sudo apt-get install -y ninja-build gcc-multilib g++-multilib make g++ pkg-config automake libtool git build-essential checkinstall libncurses-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev
- name: Build python2
sudo apt-get install -y ninja-build gcc-multilib g++-multilib python2
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1
- name: Install ICU
run: |
mkdir $GITHUB_WORKSPACE/python2-build/
cd $GITHUB_WORKSPACE/python2-build/
wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
tar xzf Python-2.7.18.tgz
cd Python-2.7.18
./configure --prefix=/usr/local/python2.7
make -j8
sudo make install
sudo update-alternatives --install /usr/bin/python python /usr/local/python2.7/bin/python2.7 1
- name: Build ICU
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu-build/
cd $GITHUB_WORKSPACE/icu-build/icu4c/source
LDFLAGS="-m32 -Wl,-rpath=$GITHUB_WORKSPACE/icu32/lib/" CFLAGS="-m32" CXXFLAGS="-m32" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu32/"
make -j8
make install
ls $GITHUB_WORKSPACE/icu32/lib/
wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu-dev_70.1-2ubuntu1_i386.deb
dpkg -X libicu-dev_70.1-2ubuntu1_i386.deb $GITHUB_WORKSPACE/icu32
- name: Build x86
env:
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_THREADING=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu32/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu32/lib/ -Wl,-rpath=$GITHUB_WORKSPACE/icu32/lib/"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu32/lib/pkgconfig
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/release/x86 $BUILD_OPTIONS
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu32/usr/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu -Wl,-rpath=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu/pkgconfig
cmake -H. -Bout/release/x86 $BUILD_OPTIONS
ninja -Cout/release/x86
- name: Run release-x86 test
env:
GC_FREE_SPACE_DIVISOR: 1
run: LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu32/lib $RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/release/x86/escargot" ${{ matrix.tc }}
- if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
run: $RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/release/x86/escargot" ${{ matrix.tc }}
build-test-on-x64-release:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
strategy:
matrix:
tc: ['octane v8 web-tooling-benchmark', 'chakracore spidermonkey new-es']
tc: ['new-es octane v8', 'chakracore spidermonkey']
build_opt: ['', '-DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON', '-DESCARGOT_SMALL_CONFIG=ON -DESCARGOT_USE_CUSTOM_LOGGING=ON']
exclude:
# exclude octane, v8, web-tooling-benchmark due to low performance incurred by SMALL_CONFIG
- tc: 'octane v8 web-tooling-benchmark'
# exclude octane, v8 due to low performance incurred by SMALL_CONFIG
- tc: 'new-es octane v8'
build_opt: '-DESCARGOT_SMALL_CONFIG=ON -DESCARGOT_USE_CUSTOM_LOGGING=ON'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
sudo apt-get update
sudo apt-get install -y ninja-build g++ pkg-config automake libtool git build-essential checkinstall libncurses-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev
- name: Build ICU(64)
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu64-build/
cd $GITHUB_WORKSPACE/icu64-build/icu4c/source
LDFLAGS="-Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib/" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu64/"
make -j8
make install
- name: Build python2
run: |
mkdir $GITHUB_WORKSPACE/python2-build/
cd $GITHUB_WORKSPACE/python2-build/
wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
tar xzf Python-2.7.18.tgz
cd Python-2.7.18
./configure --prefix=/usr/local/python2.7
make -j8
sudo make install
sudo update-alternatives --install /usr/bin/python python /usr/local/python2.7/bin/python2.7 1
sudo apt-get install -y ninja-build libicu-dev python2
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu64/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu64/lib -Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu64/lib/pkgconfig
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/release/x64 $BUILD_OPTIONS ${{ matrix.build_opt }}
cmake -H. -Bout/release/x64 $BUILD_OPTIONS ${{ matrix.build_opt }}
ninja -Cout/release/x64
- name: Run release-x64 test
env:
GC_FREE_SPACE_DIVISOR: 1
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu64/lib
# set locale
sudo locale-gen en_US.UTF-8
export LANG=en_US.UTF-8
locale
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/release/x64/escargot" ${{ matrix.tc }}
- if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
build-test-on-x86-x64-debug:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
sudo apt-get update
sudo apt-get install -y ninja-build gcc-multilib g++-multilib make g++ pkg-config automake libtool git build-essential checkinstall libncurses-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev
- name: Build ICU(32)
sudo apt-get install -y ninja-build gcc-multilib g++-multilib
- name: Install ICU
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu32-build/
cd $GITHUB_WORKSPACE/icu32-build/icu4c/source
LDFLAGS="-m32 -Wl,-rpath=$GITHUB_WORKSPACE/icu32/lib/" CFLAGS="-m32" CXXFLAGS="-m32" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu32/"
make -j8
make install
- name: Build ICU(64)
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu64-build/
cd $GITHUB_WORKSPACE/icu64-build/icu4c/source
LDFLAGS="-Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib/" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu64/"
make -j8
make install
wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu-dev_70.1-2ubuntu1_i386.deb
dpkg -X libicu-dev_70.1-2ubuntu1_i386.deb $GITHUB_WORKSPACE/icu32
wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu-dev_70.1-2ubuntu1_amd64.deb
dpkg -X libicu-dev_70.1-2ubuntu1_amd64.deb $GITHUB_WORKSPACE/icu64
- name: Build x86/x64
env:
BUILD_OPTIONS_X86: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS_X64: -DESCARGOT_MODE=debug -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS_X86: -DESCARGOT_MODE=debug -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS_X64: -DESCARGOT_MODE=debug -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/debug/x86 $BUILD_OPTIONS_X86
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/debug/x64 $BUILD_OPTIONS_X64
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu32/usr/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu -Wl,-rpath=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu/pkgconfig
cmake -H. -Bout/debug/x86 $BUILD_OPTIONS_X86
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu64/usr/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu -Wl,-rpath=$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu/pkgconfig
cmake -H. -Bout/debug/x64 $BUILD_OPTIONS_X64
ninja -Cout/debug/x86
ninja -Cout/debug/x64
- name: Run debug-mode test
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu32/lib
$RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/debug/x86/escargot" modifiedVendorTest regression-tests new-es intl sunspider-js
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu64/lib
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/debug/x64/escargot" modifiedVendorTest regression-tests new-es intl sunspider-js
build-test-on-self-hosted-linux:
if: github.repository == 'Samsung/escargot'
runs-on: [self-hosted, linux, x64, test]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build
env:
BUILD_OPTIONS: -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
LDFLAGS=" -L/usr/icu78-32/lib/ -Wl,-rpath=/usr/icu78-32/lib/" PKG_CONFIG_PATH="/usr/icu78-32/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux -DESCARGOT_ARCH=x86 -DESCARGOT_MODE=debug -DESCARGOT_TCO_DEBUG=ON $BUILD_OPTIONS
LDFLAGS=" -L/usr/icu78-32/lib/ -Wl,-rpath=/usr/icu78-32/lib/" PKG_CONFIG_PATH="/usr/icu78-32/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux_release -DESCARGOT_ARCH=x86 $BUILD_OPTIONS
LDFLAGS=" -L/usr/icu78-32/lib/ -Wl,-rpath=/usr/icu78-32/lib/" PKG_CONFIG_PATH="/usr/icu78-32/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux_release_clang -DESCARGOT_ARCH=x86 $BUILD_OPTIONS
gcc -shared -m32 -fPIC -o backtrace-hooking-32.so tools/test/test262/backtrace-hooking.c
LDFLAGS=" -L/usr/icu78-64/lib/ -Wl,-rpath=/usr/icu78-64/lib/" PKG_CONFIG_PATH="/usr/icu78-64/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux64 -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=debug -DESCARGOT_TCO_DEBUG=ON $BUILD_OPTIONS
LDFLAGS=" -L/usr/icu78-64/lib/ -Wl,-rpath=/usr/icu78-64/lib/" PKG_CONFIG_PATH="/usr/icu78-64/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux64_release -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=release $BUILD_OPTIONS
LDFLAGS=" -L/usr/icu78-64/lib/ -Wl,-rpath=/usr/icu78-64/lib/" PKG_CONFIG_PATH="/usr/icu78-64/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bbuild/out_linux64_release_clang -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=release $BUILD_OPTIONS
cmake --build build/out_linux/
cmake --build build/out_linux64/
cmake --build build/out_linux_release/
cmake --build build/out_linux_release_clang/
cmake --build build/out_linux64_release/
cmake --build build/out_linux64_release_clang/
- name: Test
run: |
LD_LIBRARY_PATH=/usr/icu78-32/lib/ GC_FREE_SPACE_DIVISOR=1 $RUNNER --arch=x86 --engine="${{ github.workspace }}/build/out_linux_release/escargot" test262
LD_LIBRARY_PATH=/usr/icu78-32/lib/ GC_FREE_SPACE_DIVISOR=1 $RUNNER --arch=x86 --engine="${{ github.workspace }}/build/out_linux_release_clang/escargot" test262
LD_LIBRARY_PATH=/usr/icu78-32/lib/ GC_FREE_SPACE_DIVISOR=1 ESCARGOT_LD_PRELOAD=${{ github.workspace }}/backtrace-hooking-32.so $RUNNER --arch=x86 --engine="${{ github.workspace }}/build/out_linux/escargot" test262
LD_LIBRARY_PATH=/usr/icu78-64/lib/ GC_FREE_SPACE_DIVISOR=1 $RUNNER --arch=x86_64 --engine="${{ github.workspace }}/build/out_linux64_release/escargot" test262
LD_LIBRARY_PATH=/usr/icu78-64/lib/ GC_FREE_SPACE_DIVISOR=1 $RUNNER --arch=x86_64 --engine="${{ github.workspace }}/build/out_linux64_release_clang/escargot" test262
LD_LIBRARY_PATH=/usr/icu78-64/lib/ python tools/kangax/run-kangax.py --engine="${{ github.workspace }}/build/out_linux64/escargot"
build-test-on-self-hosted-arm-linux:
if: github.repository == 'Samsung/escargot'
runs-on: [self-hosted, linux, arm, test]
strategy:
matrix:
compiler: [ {cxx: g++, cc: gcc}, {cxx: clang++, cc: clang} ]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bout -DCMAKE_C_COMPILER=${{ matrix.compiler.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=arm32 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=OFF -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=${{ matrix.compiler.tls }} -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
cmake --build ./out/
- name: Test
run: |
GC_FREE_SPACE_DIVISOR=1 $RUNNER --engine="${{ github.workspace }}/out/escargot" --test262-extra-arg="--skip intl402 --skip sm --skip Temporal" new-es v8 spidermonkey chakracore test262
build-test-on-self-hosted-arm64-linux:
if: github.repository == 'Samsung/escargot'
runs-on: [self-hosted, linux, arm64, test]
strategy:
matrix:
compiler: [ {cxx: g++-11, cc: gcc-11}, {cxx: clang++, cc: clang} ]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build
run: |
LDFLAGS=" -L/usr/icu78-64/lib/ -Wl,-rpath=/usr/icu78-64/lib/" PKG_CONFIG_PATH="/usr/icu78-64/lib/pkgconfig/" cmake -DCMAKE_C_COMPILER=${{ matrix.compiler.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H./ -Bout -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
cmake --build ./out/
- name: Test
run: |
export LD_LIBRARY_PATH=/usr/icu78-64/lib/
GC_FREE_SPACE_DIVISOR=1 $RUNNER --engine="${{ github.workspace }}/out/escargot" --test262-extra-arg="--skip intl402 --skip sm" test262 chakracore spidermonkey v8 new-es
build-test-on-riscv64-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build in riscv64 container
uses: uraimo/run-on-arch-action@v3
with:
arch: riscv64
distro: ubuntu22.04
# Install deps into the container. With the token, the container will be cached
# The image is cached publically like a package
githubToken: ${{ github.token }}
install: |
apt-get update
apt-get install -y cmake build-essential ninja-build pkg-config python3 git libicu-dev
run: |
cmake -H. -Bout/riscv64 -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
ninja -Cout/riscv64
python3 ./tools/run-tests.py --engine="./out/riscv64/escargot" new-es intl sunspider-js
build-test-debugger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
@ -568,9 +381,9 @@ jobs:
sudo apt-get install -y ninja-build
- name: Build
env:
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_DEBUGGER=1 -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_DEBUGGER=1 -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/debugger $BUILD_OPTIONS
cmake -H. -Bout/debugger $BUILD_OPTIONS
ninja -Cout/debugger
- name: Debugger Test
run: |
@ -580,7 +393,7 @@ jobs:
build-test-api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
@ -589,12 +402,12 @@ jobs:
sudo apt-get install -y ninja-build gcc-multilib g++-multilib
- name: Build x86/x64
env:
BUILD_OPTIONS_X86: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_THREADING=ON -DESCARGOT_DEBUGGER=1 -DESCARGOT_USE_EXTENDED_API=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=cctest -GNinja
BUILD_OPTIONS_X64: -DESCARGOT_MODE=debug -DESCARGOT_THREADING=1 -DESCARGOT_DEBUGGER=1 -DESCARGOT_USE_EXTENDED_API=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=cctest -GNinja
BUILD_OPTIONS_X86: -DCMAKE_SYSTEM_PROCSEEOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_THREADING=ON -DESCARGOT_DEBUGGER=1 -DESCARGOT_OUTPUT=cctest -GNinja
BUILD_OPTIONS_X64: -DESCARGOT_MODE=debug -DESCARGOT_THREADING=1 -DESCARGOT_DEBUGGER=1 -DESCARGOT_OUTPUT=cctest -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/cctest/x86 $BUILD_OPTIONS_X86
cmake -H. -Bout/cctest/x86 $BUILD_OPTIONS_X86
ninja -Cout/cctest/x86
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/cctest/x64 $BUILD_OPTIONS_X64
cmake -H. -Bout/cctest/x64 $BUILD_OPTIONS_X64
ninja -Cout/cctest/x64
- name: Run Test
run: |
@ -604,34 +417,37 @@ jobs:
build-test-codecache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Packages
run: |
# for i386 ICU
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y ninja-build gcc-multilib g++-multilib
sudo apt-get install -y libicu-dev:i386 # install i386 ICU
- name: Install ICU
run: |
wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu-dev_70.1-2ubuntu1_i386.deb
dpkg -X libicu-dev_70.1-2ubuntu1_i386.deb $GITHUB_WORKSPACE/icu32
wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu-dev_70.1-2ubuntu1_amd64.deb
dpkg -X libicu-dev_70.1-2ubuntu1_amd64.deb $GITHUB_WORKSPACE/icu64
- name: Build x86
env:
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_CODE_CACHE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_CODE_CACHE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/codecache/x86 $BUILD_OPTIONS
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu32/usr/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu -Wl,-rpath=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu32/usr/lib/i386-linux-gnu/pkgconfig
cmake -H. -Bout/codecache/x86 $BUILD_OPTIONS
ninja -Cout/codecache/x86
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_CODE_CACHE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_CODE_CACHE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/codecache/x64 $BUILD_OPTIONS
export CXXFLAGS="-I$GITHUB_WORKSPACE/icu64/usr/include"
export LDFLAGS="-L$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu -Wl,-rpath=$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu"
export PKG_CONFIG_PATH=$GITHUB_WORKSPACE/icu64/usr/lib/x86_64-linux-gnu/pkgconfig
cmake -H. -Bout/codecache/x64 $BUILD_OPTIONS
ninja -Cout/codecache/x64
- name: Build x64 Release Mode
env:
BUILD_OPTIONS: -DESCARGOT_MODE=release -DESCARGOT_CODE_CACHE=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/codecache/release/x64 $BUILD_OPTIONS
ninja -Cout/codecache/release/x64
- name: Run x86 test
run: |
$RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/codecache/x86/escargot" sunspider-js
@ -650,67 +466,44 @@ jobs:
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" octane-loading
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" octane-loading
rm -rf $HOME/Escargot-cache/
- name: Run x64 release test
run: |
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/release/x64/escargot" web-tooling-benchmark
rm -rf $HOME/Escargot-cache/
- name: Handle error cases
run: |
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" sunspider-js
rm $HOME/Escargot-cache/2728638815_17149
rm $HOME/Escargot-cache/3217641879501852439
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" sunspider-js
ls -1q $HOME/Escargot-cache/ | wc -l
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" sunspider-js
rm $HOME/Escargot-cache/cache_list
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/codecache/x64/escargot" sunspider-js
- if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
build-test-wasmjs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: recursive
submodules: true
- name: Install Packages
run: |
sudo apt-get update
sudo apt-get install -y ninja-build gcc-multilib g++-multilib make g++ pkg-config automake libtool git build-essential checkinstall libncurses-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev
- name: Build ICU(32)
sudo apt-get install -y ninja-build gcc-multilib g++-multilib
- name: Patch WABT
working-directory: ./third_party/wasm/wabt
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu-build/
cd $GITHUB_WORKSPACE/icu-build/icu4c/source
LDFLAGS="-m32 -Wl,-rpath=$GITHUB_WORKSPACE/icu32/lib/" CFLAGS="-m32" CXXFLAGS="-m32" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu32/"
make -j8
make install
- name: Build ICU(64)
run: |
git clone --depth 1 --single-branch -b release-78.1 https://github.com/unicode-org/icu.git $GITHUB_WORKSPACE/icu64-build/
cd $GITHUB_WORKSPACE/icu64-build/icu4c/source
LDFLAGS="-Wl,-rpath=$GITHUB_WORKSPACE/icu64/lib/" ./runConfigureICU Linux/gcc --prefix="$GITHUB_WORKSPACE/icu64/"
make -j8
make install
cp ../../../tools/test/wasm-js/wabt_patch .
patch -p0 < wabt_patch
- name: Build x86
env:
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/wasm/x86 $BUILD_OPTIONS
cmake -H. -Bout/wasm/x86 $BUILD_OPTIONS
ninja -Cout/wasm/x86
- name: Build x64
env:
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -DESCARGOT_OUTPUT=shell -GNinja
BUILD_OPTIONS: -DESCARGOT_MODE=debug -DESCARGOT_WASM=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/wasm/x64 $BUILD_OPTIONS
cmake -H. -Bout/wasm/x64 $BUILD_OPTIONS
ninja -Cout/wasm/x64
- name: Run x86 test
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu32/lib
$RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/wasm/x86/escargot" wasm-js
run: $RUNNER --arch=x86 --engine="$GITHUB_WORKSPACE/out/wasm/x86/escargot" wasm-js
- name: Run x64 test
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/icu64/lib
$RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/wasm/x64/escargot" wasm-js
- if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
timeout-minutes: 60
run: $RUNNER --arch=x86_64 --engine="$GITHUB_WORKSPACE/out/wasm/x64/escargot" wasm-js

View file

@ -1,11 +0,0 @@
[general]
profile = profile.tizen
[profile.tizen]
repos = repo.tizen_base_reference,repo.tizen_reference
[repo.tizen_reference]
url = https://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Unified/reference/repos/standard/packages/
[repo.tizen_base_reference]
url = https://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Base/reference/repos/standard/packages/

View file

@ -1,322 +0,0 @@
name: Release
on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
env:
RUNNER: tools/run-tests.py
BUILD_OPTIONS: -DESCARGOT_MODE=release -DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF -DESCARGOT_DEPLOY=ON -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja
jobs:
build-macOS:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-15, macos-latest]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install Packages
run: |
brew update
brew install ninja icu4c zip
- name: Build x64
run: |
# check cpu
sysctl -a | grep machdep.cpu
# add icu path to pkg_config_path
export PKG_CONFIG_PATH="$(brew --prefix icu4c)/lib/pkgconfig"
echo $PKG_CONFIG_PATH
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -H. -Bout/ $BUILD_OPTIONS
ninja -Cout/
- name: Check
run: |
file out/escargot
strip out/escargot
# set deploy directory
mkdir -p deploy
# set escargot
cp out/escargot ./deploy/.
LIBS=$(otool -L ./deploy/escargot | grep "icu" | awk '{print $1}')
for LIB in $LIBS; do
BASENAME=$(basename "$LIB")
install_name_tool -change "$LIB" "@executable_path/$BASENAME" deploy/escargot
done
# set icu libs
ICU_LIBS=("libicuuc" "libicui18n" "libicudata")
ICU_SOURCE_PATH="$(brew --prefix icu4c)/lib"
ICU_VERSION=$(find "$ICU_SOURCE_PATH" -name "libicuuc.*.dylib" | grep -oE '\.[0-9]+\.' | head -n 1 | tr -d '.')
if [ -z "$ICU_VERSION" ]; then
echo "ICU version could not be detected."
exit 1
else
echo "Detected ICU Version: $ICU_VERSION"
fi
for LIB in "${ICU_LIBS[@]}"; do
cp -a $ICU_SOURCE_PATH/$LIB.*.dylib ./deploy/.
install_name_tool -id "@loader_path/$LIB.$ICU_VERSION.dylib" "./deploy/$LIB.$ICU_VERSION.dylib"
done
# check results
echo "Check results..."
ls ./deploy
otool -L ./deploy/escargot
otool -L ./deploy/libicu*.dylib
# Ad-hoc sign
set -e
cd deploy
for f in libicu*.dylib; do [ -e "$f" ] || continue; codesign -f -s - "$f"; done
codesign --force --deep -s - ./escargot
for f in ./escargot libicu*.dylib; do [ -e "$f" ] || continue; codesign --verify --strict --verbose=6 "$f"; done
cd ..
# run test
$RUNNER --engine="$GITHUB_WORKSPACE/deploy/escargot" new-es
# zip results
if [ "${{ matrix.os }}" == "macos-15" ]; then
zip -j escargot-mac64.zip deploy/*
elif [ "${{ matrix.os }}" == "macos-latest" ]; then
zip -j escargot-mac64arm.zip deploy/*
fi
- name: Upload mac64
if: ${{ matrix.os == 'macos-15' }}
uses: actions/upload-artifact@v4
with:
name: build-artifact-mac64
path: ./escargot-mac64.zip
- name: Upload mac64arm
if: ${{ matrix.os == 'macos-latest' }}
uses: actions/upload-artifact@v4
with:
name: build-artifact-mac64arm
path: ./escargot-mac64arm.zip
build-linux:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install Packages
run: |
# for i386 ICU
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y ninja-build libicu-dev gcc-multilib g++-multilib zip patchelf
sudo apt-get install -y libicu-dev:i386 # install i386 ICU
- name: Build x86/x64
run: |
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/x86 -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=x86 -DESCARGOT_TEMPORAL=ON $BUILD_OPTIONS
cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -H. -Bout/x64 -DESCARGOT_TEMPORAL=ON $BUILD_OPTIONS
ninja -Cout/x86
ninja -Cout/x64
- name: Check
run: |
file out/x86/escargot
file out/x64/escargot
strip out/x86/escargot
strip out/x64/escargot
# set locale
sudo locale-gen en_US.UTF-8
export LANG=en_US.UTF-8
locale
# set deploy directory and copy escargot binary
mkdir -p deploy-x86
mkdir -p deploy-x64
cp out/x86/escargot ./deploy-x86/.
cp out/x64/escargot ./deploy-x64/.
# set icu libs
ldd deploy-x86/escargot | grep "icu" | grep "=>" | awk '{print $3}' | xargs -I '{}' cp '{}' deploy-x86/
ldd deploy-x64/escargot | grep "icu" | grep "=>" | awk '{print $3}' | xargs -I '{}' cp '{}' deploy-x64/
for LIB in ./deploy-x86/libicu*; do
patchelf --set-rpath '$ORIGIN' "$LIB"
done
for LIB in ./deploy-x64/libicu*; do
patchelf --set-rpath '$ORIGIN' "$LIB"
done
# check results
echo "Check results..."
ls ./deploy-x86
ldd deploy-x86/escargot
ldd deploy-x86/libicu*
ls ./deploy-x64
ldd deploy-x64/escargot
ldd deploy-x64/libicu*
# run test
$RUNNER --engine="$GITHUB_WORKSPACE/deploy-x86/escargot" new-es
$RUNNER --engine="$GITHUB_WORKSPACE/deploy-x64/escargot" new-es
# zip results
zip -j escargot-linux-x86.zip deploy-x86/*
zip -j escargot-linux-x64.zip deploy-x64/*
- name: Upload
uses: actions/upload-artifact@v4
with:
name: build-artifact-linux
path: escargot-linux-*.zip
build-windows:
runs-on: windows-2022
strategy:
matrix:
arch: [x86, x64]
steps:
- name: Set git cllf config
run: |
git config --global core.autocrlf input
git config --global core.eol lf
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: szenius/set-timezone@v2.0
with:
timezoneWindows: "Pacific Standard Time"
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0"
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
with:
sdk-version: 26100
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Download and Install Visual C++ Redistributable
shell: powershell
run: |
$vcRedistUrl64 = "https://aka.ms/vs/17/release/vc_redist.x64.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath64 = "$env:TEMP\vc_redist.x64.exe"
$vcRedistUrl32 = "https://aka.ms/vs/17/release/vc_redist.x86.exe" # Or the appropriate URL for your target architecture/version
$vcRedistPath32 = "$env:TEMP\vc_redist.x86.exe"
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl64"
Invoke-WebRequest -Uri $vcRedistUrl64 -OutFile $vcRedistPath64
Write-Host "Downloading Visual C++ Redistributable from $vcRedistUrl32"
Invoke-WebRequest -Uri $vcRedistUrl32 -OutFile $vcRedistPath32
Write-Host "Installing Visual C++ Redistributable silently"
Start-Process -FilePath $vcRedistPath64 -ArgumentList "/install /quiet /norestart" -Wait
Start-Process -FilePath $vcRedistPath32 -ArgumentList "/install /quiet /norestart" -Wait
Write-Host "Visual C++ Redistributable installation complete."
- uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: ${{ matrix.arch }}
sdk: "10.0.26100.0"
- name: Install zip if not available
run: |
if (-Not (Get-Command zip -ErrorAction SilentlyContinue)) {
choco install zip -y
}
- name: Build ${{ matrix.arch }}
run: |
CMake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -DESCARGOT_ARCH=${{ matrix.arch }} -Bout/ -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_WASM=ON -DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_SHADOWREALM=ON -G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=release
CMake --build out/ --config Release
- name: Check
run: |
python tools\run-tests.py --engine=%cd%\out\escargot.exe new-es
rename out\escargot.exe escargot-win-${{ matrix.arch }}.exe
zip -j escargot-win-${{ matrix.arch}}.zip out\escargot-win-${{ matrix.arch }}.exe
shell: cmd
- name: Upload
uses: actions/upload-artifact@v4
with:
name: build-artifact-win-${{ matrix.arch }}
path: escargot-win-${{ matrix.arch }}.zip
check-build-mac64:
needs: [build-macOS]
runs-on: macos-15
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-artifact-mac64
merge-multiple: true
- name: Check
run: |
unzip artifacts/escargot-mac64.zip -d artifacts
otool -L artifacts/escargot
otool -L artifacts/*.dylib
$RUNNER --engine="$GITHUB_WORKSPACE/artifacts/escargot" new-es
check-build-mac64arm:
needs: [build-macOS]
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-artifact-mac64arm
merge-multiple: true
- name: Check
run: |
unzip artifacts/escargot-mac64arm.zip -d artifacts
otool -L artifacts/escargot
otool -L artifacts/*.dylib
$RUNNER --engine="$GITHUB_WORKSPACE/artifacts/escargot" new-es
check-build-linux:
needs: [build-linux]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-artifact-linux
merge-multiple: true
- name: Check
run: |
dpkg -l | grep libicu-dev
mkdir -p result-x86
mkdir -p result-x64
unzip artifacts/escargot-linux-x86.zip -d result-x86
unzip artifacts/escargot-linux-x64.zip -d result-x64
ldd result-x86/escargot
ldd result-x86/libicu*
ldd result-x64/escargot
ldd result-x64/libicu*
$RUNNER --engine="$GITHUB_WORKSPACE/result-x86/escargot" new-es
$RUNNER --engine="$GITHUB_WORKSPACE/result-x64/escargot" new-es
update-release:
needs: [check-build-mac64, check-build-mac64arm, check-build-linux, build-windows]
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-artifact-*
merge-multiple: true
- name: Upload to release
uses: softprops/action-gh-release@v2
with:
files: |
artifacts/escargot-*

7
.gitignore vendored
View file

@ -1,5 +1,5 @@
#error_report
/escargot
escargot
escargot.x*
.project
.cproject
@ -18,7 +18,7 @@ cscope.out
#memps
escargot.asm
escargot.elf
out/*
out
build.ninja
rules.ninja
.ninja_deps
@ -38,6 +38,5 @@ cmake_install.cmake
#etc
.vscode
EscargotInfo.h
third_party/wasm/config.h
escargot.pc
escargot_generated/*
.vs/*

19
.gitmodules vendored
View file

@ -15,18 +15,17 @@
url = https://github.com/chromium/octane.git
ignore = untracked
[submodule "test/kangax"]
path = test/kangax
url = https://github.com/kangax/compat-table.git
path = test/kangax
url = https://github.com/kangax/compat-table.git
ignore = untracked
[submodule "third_party/googletest"]
path = third_party/googletest
url = https://github.com/google/googletest.git
path = third_party/googletest
url = https://github.com/google/googletest.git
ignore = untracked
[submodule "third_party/walrus"]
path = third_party/walrus
url = https://github.com/Samsung/walrus.git
[submodule "third_party/wasm/wabt"]
path = third_party/wasm/wabt
url = https://github.com/WebAssembly/wabt
ignore = untracked
[submodule "test/web-tooling-benchmark"]
path = test/web-tooling-benchmark
url = https://github.com/v8/web-tooling-benchmark
ignore = untracked
path = test/web-tooling-benchmark
url = https://github.com/v8/web-tooling-benchmark

88
.jenkins/Jenkinsfile vendored Normal file
View file

@ -0,0 +1,88 @@
def isPr() {
env.CHANGE_ID != null
}
node {
currentBuild.displayName = "Escargot test on x86"
try {
stage("Get source") {
def url = 'https://github.com/Samsung/escargot.git'
if (isPr()) {
def refspec = "+refs/pull/${env.CHANGE_ID}/head:refs/remotes/origin/PR-${env.CHANGE_ID} +refs/heads/master:refs/remotes/origin/master"
def extensions = [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin", mergeTarget: "PR-${env.CHANGE_ID}"]]]
checkout([
$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: extensions,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: url
]]
])
} else {
def refspec = "+refs/heads/master:refs/remotes/origin/master"
def extensions = []
checkout([
$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'WipeWorkspace']],
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: url
]]
])
}
}
stage('Submodule update') {
sh 'git submodule update --init test third_party/GCutil'
}
stage('Prepare build(gcc)') {
sh 'LDFLAGS=" -L/usr/icu32/lib/ -Wl,-rpath=/usr/icu32/lib/" PKG_CONFIG_PATH="/usr/icu32/lib/pkgconfig/" cmake -H./ -Bbuild/out_linux -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x86 -DESCARGOT_MODE=debug -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja'
sh 'LDFLAGS=" -L/usr/icu32/lib/ -Wl,-rpath=/usr/icu32/lib/" PKG_CONFIG_PATH="/usr/icu32/lib/pkgconfig/" cmake -H./ -Bbuild/out_linux_release -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x86 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja'
sh 'gcc -shared -m32 -fPIC -o backtrace-hooking-32.so tools/test/test262/backtrace-hooking.c'
sh 'LDFLAGS=" -L/usr/icu64/lib/ -Wl,-rpath=/usr/icu64/lib/" PKG_CONFIG_PATH="/usr/icu64/lib/pkgconfig/" cmake -H./ -Bbuild/out_linux64 -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=debug -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja'
sh 'LDFLAGS=" -L/usr/icu64/lib/ -Wl,-rpath=/usr/icu64/lib/" PKG_CONFIG_PATH="/usr/icu64/lib/pkgconfig/" cmake -H./ -Bbuild/out_linux64_release -DESCARGOT_HOST=linux -DESCARGOT_ARCH=x64 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja'
}
stage('Build(gcc)') {
parallel (
'release-build' : {
sh 'cd build/out_linux/; ninja '
sh 'cd build/out_linux64/; ninja'
},
'debug-build' : {
sh 'cd build/out_linux_release/; ninja'
sh 'cd build/out_linux64_release/; ninja'
},
)
}
stage('Running test') {
timeout(30) {
parallel (
'release-32bit-test262' : {
sh 'GC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --arch=x86 --engine="${WORKSPACE}/build/out_linux_release/escargot" test262'
},
'debug-32bit-test262' : {
sh 'GC_FREE_SPACE_DIVISOR=1 ESCARGOT_LD_PRELOAD=${WORKSPACE}/backtrace-hooking-32.so tools/run-tests.py --arch=x86 --engine="${WORKSPACE}/build/out_linux/escargot" test262'
},
'release-64bit-test262' : {
sh 'GC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --arch=x86_64 --engine="${WORKSPACE}/build/out_linux64_release/escargot" test262'
},
'kangax test-suites' : {
sh 'python tools/kangax/run-kangax.py --engine="${WORKSPACE}/build/out_linux64/escargot"'
},
)
}
}
} catch (e) {
throw e
} finally {
cleanWs()
}
}

91
.jenkins/JenkinsfileArm Normal file
View file

@ -0,0 +1,91 @@
def isPr() {
env.CHANGE_ID != null
}
node {
currentBuild.displayName = "Escargot test on Arm"
try {
stage("Get source") {
def url = 'https://github.com/Samsung/escargot.git'
if (isPr()) {
def refspec = "+refs/pull/${env.CHANGE_ID}/head:refs/remotes/origin/PR-${env.CHANGE_ID} +refs/heads/master:refs/remotes/origin/master"
def extensions = [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin", mergeTarget: "PR-${env.CHANGE_ID}"]]]
checkout([
$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: extensions,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: url
]]
])
} else {
def refspec = "+refs/heads/master:refs/remotes/origin/master"
def extensions = []
checkout([
$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'WipeWorkspace']],
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: url
]]
])
}
}
stage('Submodule update') {
sh 'git submodule update --init test third_party/GCutil'
}
def arm32RemoteInfo = [:]
arm32RemoteInfo.name = 'arm32-docker'
arm32RemoteInfo.host = 'localhost'
arm32RemoteInfo.port = 11111
arm32RemoteInfo.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: 'arm32docker', passwordVariable: 'passwordVariable', usernameVariable: 'usernameVariable')]) {
arm32RemoteInfo.user = usernameVariable
arm32RemoteInfo.password = passwordVariable
}
stage('prepare arm32 workspace') {
sshCommand remote: arm32RemoteInfo, command: "rm -rf escargot escargot.zip"
sshCommand remote: arm32RemoteInfo, command: "pwd"
sh "zip -r escargot.zip ./*"
sshPut remote: arm32RemoteInfo, from: "escargot.zip", into: "./"
sshCommand remote: arm32RemoteInfo, command: "unzip escargot.zip -d escargot"
}
stage('Build arm32') {
sshCommand remote: arm32RemoteInfo, command: "\
cd escargot;\
cmake -H./ -Bout -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=arm32 -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja;\
cmake --build ./out/;\
"
}
stage('Build aarch64') {
sh 'cmake -H./ -Bout -DESCARGOT_MODE=release -DESCARGOT_THREADING=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TEST=ON -DESCARGOT_OUTPUT=shell -GNinja'
sh 'cmake --build ./out/'
}
stage('Running test') {
timeout(60) {
parallel (
'arm32' : {
sshCommand remote: arm32RemoteInfo, command: "\
cd escargot;\
GC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --engine='/root/escargot/out/escargot' --extra-arg='--skip intl402' new-es v8 spidermonkey chakracore test262"
},
'aarch64' : {
sh '#!/bin/bash\nGC_FREE_SPACE_DIVISOR=1 tools/run-tests.py --engine="${WORKSPACE}/out/escargot" --extra-arg="--skip intl402" new-es v8 spidermonkey chakracore test262'
},
)
}
}
} catch (e) {
throw e
} finally {
cleanWs()
}
}

View file

@ -4,7 +4,6 @@ PROJECT (ESCARGOT)
# CONFIGURATION
SET (CMAKE_VERBOSE_MAKEFILE true)
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
MESSAGE(STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME})
MESSAGE(STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR})
@ -44,9 +43,12 @@ ENDIF()
IF (NOT DEFINED ESCARGOT_OUTPUT)
SET (ESCARGOT_OUTPUT "shell")
ENDIF()
IF (NOT DEFINED ESCARGOT_THREADING)
SET (ESCARGOT_THREADING ON)
ENDIF()
MESSAGE(STATUS "Escargot Arch: " ${ESCARGOT_ARCH})
MESSAGE(STATUS "Escargot Host: " ${ESCARGOT_HOST})
MESSAGE(STATUS "Escargot Mode: " ${ESCARGOT_MODE})
MESSAGE(STATUS "Escargot Output: " ${ESCARGOT_OUTPUT})
SET (ESCARGOT_TARGET escargot)
SET (ESCARGOT_CCTEST_TARGET cctest)
@ -60,31 +62,3 @@ INCLUDE (${PROJECT_SOURCE_DIR}/build/escargot.cmake)
# Pkgconfig
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/packaging/escargot.pc.in ${CMAKE_BINARY_DIR}/escargot.pc @ONLY)
IF (ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY AND ESCARGOT_TLS_ACCESS_BY_ADDRESS)
MESSAGE(FATAL_ERROR "You cannot enable ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY and ESCARGOT_TLS_ACCESS_BY_ADDRESS at same time")
ENDIF()
MESSAGE(STATUS "Escargot Arch: " ${ESCARGOT_ARCH})
MESSAGE(STATUS "Escargot Host: " ${ESCARGOT_HOST})
MESSAGE(STATUS "Escargot Mode: " ${ESCARGOT_MODE})
MESSAGE(STATUS "Escargot Output: " ${ESCARGOT_OUTPUT})
MESSAGE(STATUS "--------------------------------------------------------------------------------")
MESSAGE(STATUS "ESCARGOT_DEFINITIONS: " ${ESCARGOT_DEFINITIONS})
MESSAGE(STATUS "ESCARGOT_CXXFLAGS: " ${ESCARGOT_CXXFLAGS})
MESSAGE(STATUS "ESCARGOT_LDFLAGS: " ${ESCARGOT_LDFLAGS})
MESSAGE(STATUS "ESCARGOT_INCDIRS: " ${ESCARGOT_INCDIRS})
MESSAGE(STATUS "ESCARGOT_LIBRARIES: " ${ESCARGOT_LIBRARIES})
MESSAGE(STATUS "ESCARGOT_LIBICU_SUPPORT: " ${ESCARGOT_LIBICU_SUPPORT})
MESSAGE(STATUS "ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN: " ${ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN})
MESSAGE(STATUS "ESCARGOT_SMALL_CONFIG: " ${ESCARGOT_SMALL_CONFIG})
MESSAGE(STATUS "ESCARGOT_CODE_CACHE: " ${ESCARGOT_CODE_CACHE})
MESSAGE(STATUS "ESCARGOT_WASM: " ${ESCARGOT_WASM})
MESSAGE(STATUS "ESCARGOT_THREADING: " ${ESCARGOT_THREADING})
MESSAGE(STATUS "ESCARGOT_TLS_ACCESS_BY_ADDRESS: " ${ESCARGOT_TLS_ACCESS_BY_ADDRESS})
MESSAGE(STATUS "ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY: " ${ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY})
MESSAGE(STATUS "ESCARGOT_EXPORT_ALL: " ${ESCARGOT_EXPORT_ALL})
MESSAGE(STATUS "ESCARGOT_TCO: " ${ESCARGOT_TCO})
MESSAGE(STATUS "ESCARGOT_TEMPORAL: " ${ESCARGOT_TEMPORAL})
MESSAGE(STATUS "ESCARGOT_SHADOWREALM: " ${ESCARGOT_SHADOWREALM})
MESSAGE(STATUS "ESCARGOT_TEST: " ${ESCARGOT_TEST})

View file

@ -1,33 +0,0 @@
MIT-style License
Copyright (c) 1988-1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
Copyright (c) 1999-2011 Hewlett-Packard Development Company, L.P.
Copyright (c) 2004-2005 Andrei Polushin
Copyright (c) 2007 Free Software Foundation, Inc.
Copyright (c) 2008-2022 Ivan Maidanski
Copyright (c) 2011 Ludovic Courtes
Copyright (c) 2018 Petter A. Urkedal
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
Permission is hereby granted to use or copy this program
for any purpose, provided the above notices are retained on all copies.
Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.
Several files (gc/gc_allocator.h, extra/msvc_dbg.c) come with slightly
different licenses, though they are all similar in spirit (the exact
licensing terms are given at the beginning of the corresponding source file).
A few of the files needed to use the GNU-style build procedure come with
a modified GPL license that appears not to significantly restrict use of
the collector, though use of those files for a purpose other than building
the collector may require the resulting code to be covered by the GPL.

199
README.md
View file

@ -1,72 +1,12 @@
# Escargot
# Return-Check Version of Escargot
[![License](https://img.shields.io/badge/License-LGPL%20v2.1-blue.svg)](LICENSE)
[![GitHub release (latestSemVer)](https://img.shields.io/github/v/release/Samsung/escargot)](https://github.com/Samsung/escargot/releases)
[![Actions Status](https://github.com/Samsung/escargot/workflows/ES-Actions/badge.svg)](https://github.com/Samsung/escargot/actions/workflows/es-actions.yml)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/21647/badge.svg)](https://scan.coverity.com/projects/samsung-escargot)
[![codecov](https://codecov.io/gh/Samsung/escargot/branch/master/graph/badge.svg?token=DX8CN6E7A8)](https://codecov.io/gh/Samsung/escargot)
## Prerequisites
Escargot is a lightweight JavaScript engine developed by [Samsung](https://github.com/Samsung), designed specifically for resource-constrained environments. It is optimized for performance and low memory usage, making it ideal for use in embedded systems, IoT devices, and other applications where resources are limited.
Key features of Escargot include:
* **ECMAScript Compliance**: Escargot supports a significant portion of the latest ECMAScript version ([ECMAScript 2025](https://262.ecma-international.org/16.0/)), ensuring compatibility with modern JavaScript standards while maintaining a lightweight footprint.
* **Memory Efficiency**: The engine is designed with memory constraints in mind, making it suitable for devices with limited RAM and storage.
* **Performance Optimization**: Escargot implements various optimization techniques to ensure fast execution of JavaScript code, even on low-power devices.
* **Extensibility**: The engine can be customized and extended to meet the specific needs of different applications, providing flexibility for developers.
Escargot is an open-source project that allows developers to contribute to its development or use it in their own projects, while also powering several services in Samsung products. The engine's design prioritizes simplicity and efficiency, making it an excellent choice for developers working in embedded or resource-limited environments.
## Contents 📋
* [Building](#Building-)
* [Linux](#Linux)
* [macOS](#macOS)
* [Android](#Android)
* [Windows](#Windows)
* [Testing](#Testing-)
* [Contributing](#Contributing-)
* [Research Papers](#Research-Papers-)
* [License](#License-)
## Building 🛠️
### Supported Platforms and Architectures
| **OS** | **Architecture** |
|-|-|
| **Linux(Ubuntu)** | x86/x64/arm/aarch64 |
| macOS | x64/aarch64 |
| Windows | Win32/x64 |
| Android | x86/x64/arm/aarch64 |
### Build Options
The following build options are supported when generating build rules using cmake.
| **Option** | **Description** | **Flag** | **Value** | **Default** |
|-|-|-|-|-|
| **HOST** | Choose target platform | -DESCARGOT_HOST | linux/darwin/android/windows | |
| **ARCH** | Choose target architecture | -DESCARGOT_ARCH | x64/x86/arm/aarch64 | |
| **MODE** | Choose release/debug mode | -DESCARGOT_MODE | release/debug | release |
| **OUTPUT** | Choose build output type | -DESCARGOT_OUTPUT | shared_lib/static_lib/shell/cctest | shell |
| **LIBICU** | Include libicu library | -DESCARGOT_LIBICU_SUPPORT | ON/OFF | ON |
| **WASM** | Enable WebAssembly support | -DESCARGOT_WASM | ON/OFF | OFF |
| **CODE_CACHE** | Enable code cache | -DESCARGOT_CODE_CACHE | ON/OFF | OFF |
| **TCO** | Enable tail call optimization | -DESCARGOT_TCO | ON/OFF | OFF |
| **THREADING** | Enable threading features (e.g. Atomics, SharedArrayBuffer) | -DESCARGOT_THREADING | ON/OFF | ON |
| **TLS_ADDRESS_OFFSET** | Enable thread local storge access optimization(offset) | -DESCARGOT_TLS_ACCESS_BY_ADDRESS | ON/OFF | OFF |
| **TLS_PTHREAD_KEY** | Enable thread local storge access optimization(pthread_key) | -DESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY | ON/OFF | OFF |
| **TEMPORAL** | Enable Temporal support | -ESCARGOT_TEMPORAL | ON/OFF | OFF |
| **SHADOWREALM** | Enable ShadowRealm support | -ESCARGOT_SHADOWREALM | ON/OFF | OFF |
| **SMALL_CONFIG** | Enable aggressive memory optimizations for tiny devices | -DESCARGOT_SMALL_CONFIG | ON/OFF | OFF |
| **TEST** | Enable additional features used only for testing | -DESCARGOT_TEST | ON/OFF | OFF |
| **DEBUGGER** | Enable Debug server | -DESCARGOT_DEBUGGER | ON/OFF | OFF |
### Linux
#### On Ubuntu Linux
General build prerequisites:
```sh
sudo apt-get install autoconf automake cmake libtool libicu-dev ninja-build pkg-config
sudo apt-get install autoconf automake cmake libtool libicu-dev ninja-build
```
Prerequisites for x86-64-to-x86 compilation:
@ -75,120 +15,47 @@ sudo apt-get install gcc-multilib g++-multilib
sudo apt-get install libicu-dev:i386
```
Build Escargot:
## Build Escargot
build core runtime of Escargot engine (excluding intl, temporal etc)
```sh
git submodule update --init third_party # update submodules
cmake -DESCARGOT_MODE=release -DESCARGOT_OUTPUT=shell -GNinja
ninja
git clone https://github.com/Samsung/escargot.git -b return-check
cd escargot
git submodule update --init third_party
cmake -H. -Bout/test/release -DESCARGOT_HOST=linux -DESCARGOT_ARCH=[x86|x64|arm|aarch64] -DESCARGOT_MODE=release -DESCARGOT_OUTPUT=shell -DESCARGOT_THREADING=ON -DESCARGOT_TEST=ON -GNinja
ninja -Cout/test/release
```
### macOS
## Testing
General build prerequisites:
#### octane
Using test runner
```sh
brew install autoconf automake cmake icu4c libtool ninja pkg-config
# add icu path to pkg_config_path (x64)
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
# add icu path to pkg_config_path (arm64)
export PKG_CONFIG_PATH="/opt/homebrew/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
tools/run-tests.py --engine=ESCARGOT_BINARY_PATH octane
```
Build Escargot:
Or directly run octane benchmarks
```sh
git submodule update --init third_party # update submodules
cmake -DESCARGOT_MODE=release -DESCARGOT_OUTPUT=shell -GNinja
ninja
cd test/octane/
./escargot run.js
```
#### sunspider
Using test runner
```sh
tools/run-tests.py --engine=ESCARGOT_BINARY_PATH sunspider-js
```
### Android
#### kraken
Build prerequisites on Ubuntu:
download kraken benchmark
```sh
sudo apt install openjdk-17-jdk # require java 17
git clone https://github.com/mozilla-it/krakenbenchmark.mozilla.org.git
```
Build Escargot using gradle:
run kraken benchmark
```sh
git submodule update --init third_party # update submodules
export ANDROID_SDK_ROOT=.... # set your android SDK root first
cd build/android/
./gradlew bundleReleaseAar # build escargot AAR
./gradlew bundleHostJar # bundle jar for host
./gradlew javadocJar # create java doc
./gradlew sourcesJar # create sources jar
./gradlew assembleDebug # build debug test shell
./gradlew :escargot:connectedDebugAndroidTest # run escargot-jni tests on android device
./gradlew :escargot:testDebugUnitTest # run escargot-jni tests on host
cd krakenbenchmark.mozilla.org
./sunspider --shell ESCARGOT_BINARY_PATH --suite kraken-1.1
```
### Windows
Install VS2022 with cmake and ninja.
Open [ x86 Native Tools Command Prompt for VS 2022 | x64 Native Tools Command Prompt for VS 2022 ]
```sh
git submodule update --init third_party # update submodules
CMake -G "Visual Studio 17 2022" -DCMAKE_SYSTEM_NAME=[ Windows | WindowsStore ] -DCMAKE_SYSTEM_VERSION:STRING="10.0" -DCMAKE_SYSTEM_PROCESSOR=[ x86 | x64 ] -DCMAKE_GENERATOR_PLATFORM=[ Win32 | x64 ],version=10.0.18362.0 -DESCARGOT_ARCH=[ x86 | x64 ] -DESCARGOT_MODE=release -Bout -DESCARGOT_HOST=windows -DESCARGOT_OUTPUT=shell -DESCARGOT_LIBICU_SUPPORT=ON -DESCARGOT_THREADING=ON
cd out
msbuild ESCARGOT.sln /property:Configuration=Release /p:platform=[ Win32 | x64 ]
```
## Debugger
Make sure Escargot is built with the `-DESCARGOT_DEBUGGER=1` flag (off by default) enabled;
then start Escargot with the `--start-debug-server` option.
### Connect using a debugger client
- Escargot python debugger
- run `./tools/debugger/debugger.py`; It will automatically connect to a debug server on the default port `6501`
- run `./tools/debugger/debugger.py --help` for a list of options
- [Visual Studio Code extension](https://github.com/Samsung/escargot-vscode-extension/?tab=readme-ov-file#how-to-use)
- Chrome Devtools `⚠️ Early in development ⚠️`
- Initial setup:
- Navigate to [chrome://inspect](chrome://inspect)
- Make sure *Discover network targets* is enabled; click configure
- Add `localhost:6501` as a target; click Done
- Usage:
- The started debug server will be listed in the *Remote Target* list (If it is not, the page may need to be reloaded using the browser reload button)
- Click `inspect`
- A new window with the Chrome Devtools debugger UI will open
## Testing ✅
Escargot supports various benchmark sets, which can be run using the [tools/run-tests.py](https://github.com/Samsung/escargot/blob/master/tools/run-tests.py) script.
| Benchmark | flag |
| --- | --- |
| SunSpider 1.0.2 | `sunspider` |
| [Octane 2.0](https://github.com/chromium/octane.git) | `octane` |
| [test262](https://github.com/tc39/test262.git) | `test262` |
| [Web Tooling Benchmark](https://github.com/v8/web-tooling-benchmark) | `web-tooling-benchmark` |
| SpiderMonkey (vendor-made) | `spidermonkey` |
| ChakraCore (vendor-made) | `chakracore` |
| V8 (vendor-made) | `v8` |
Run each benchmark separately or all together as shown below:
```sh
tools/run-tests.py --engine=./out/linux/x64/release/escargot web-tooling-benchmark
tools/run-tests.py --engine=./out/linux/x64/release/escargot spidermonkey test262 v8
```
## Contributing 💡
Escargot welcomes contributions from developers in any form, wheter it's code, documentation, bug reports, or suggestions. By contributing to the project, you agree to license your contributions under the [LGPL-2.1](https://github.com/Samsung/escargot/blob/master/LICENSE) license.
#### ❗ Vulnerability Reporting
⚠️ If you identify any vulnerabilities, please report them through the [Issues page](https://github.com/Samsung/escargot/issues). *Reports sent via other channels may not be considered or may be processed with delays*. Please note that our project assumes the execution of valid JavaScript source code only. Handling of invalid source code is not within the main scope of this project and might not be addressed.
## Research Papers 📝
* [Dynamic code compression for JavaScript engine](https://doi.org/10.1002/spe.3186)
Software: Practice and Experience Vol. 53 (5), pp. 1196-1217, 2023
* [Tail Call Optimization Tailored for Native Stack Utilization in JavaScript Runtimes](https://doi.org/10.1109/ACCESS.2024.3441750)
IEEE Access Vol. 12, pp. 111801-111817, 2024
## License 📜
Escargot is open-source software primarily licensed under [LGPL-2.1](https://github.com/Samsung/escargot/blob/master/LICENSE), with some components covered by other licenses. Complete license and copyright information can be found in the source code.
results would be stored in `kraken-1.1-results` directory

View file

@ -1 +1 @@
v4.3.0
v4.0.1

View file

@ -1,7 +1,12 @@
*.iml
.gradle
/local.properties
/.idea/*
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
<bytecodeTargetLevel target="11" />
</component>
</project>

View file

@ -4,9 +4,9 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View file

@ -2,17 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../test/kangax" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../test/octane" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../test/test262" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../test/vendortest" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../test/web-tooling-benchmark" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/GCutil" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/googletest" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/walrus" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/walrus/third_party/sljit" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/walrus/third_party/uvwasi" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/walrus/third_party/wasm-c-api" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../third_party/wasm/wabt" vcs="Git" />
</component>
</project>

View file

@ -4,12 +4,12 @@ plugins {
android {
namespace 'com.samsung.lwe.escargot.shell'
compileSdk 34
compileSdk 33
defaultConfig {
applicationId "com.samsung.lwe.escargot.shell"
minSdk 28
targetSdk 34
targetSdk 33
versionCode 1
versionName "1.0"

View file

@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"

View file

@ -5,37 +5,29 @@ import androidx.appcompat.app.AppCompatActivity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import com.samsung.lwe.escargot.Bridge;
import com.samsung.lwe.escargot.Context;
import com.samsung.lwe.escargot.Evaluator;
import com.samsung.lwe.escargot.Globals;
import com.samsung.lwe.escargot.JavaScriptArrayObject;
import com.samsung.lwe.escargot.JavaScriptJavaCallbackFunctionObject;
import com.samsung.lwe.escargot.JavaScriptString;
import com.samsung.lwe.escargot.JavaScriptValue;
import com.samsung.lwe.escargot.Memory;
import com.samsung.lwe.escargot.VMInstance;
import com.samsung.lwe.escargot.util.MultiThreadExecutor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Optional;
public class MainActivity extends AppCompatActivity {
@ -90,9 +82,9 @@ public class MainActivity extends AppCompatActivity {
{
Context finalContext = context;
context.getGlobalObject().set(context, JavaScriptString.create("print"), JavaScriptJavaCallbackFunctionObject.create(context, "print", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
context.getGlobalObject().set(context, JavaScriptValue.create("print"), JavaScriptJavaCallbackFunctionObject.create(context, "print", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
public Optional<JavaScriptValue> callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
StringBuffer sb = new StringBuffer();
sb.append(str);
sb.append('\n');
@ -126,9 +118,9 @@ public class MainActivity extends AppCompatActivity {
}
}));
context.getGlobalObject().set(context, JavaScriptString.create("load"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
context.getGlobalObject().set(context, JavaScriptValue.create("load"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
public Optional<JavaScriptValue> callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
Optional<JavaScriptString> s = javaScriptValues[0].toString(finalContext);
if (s.isPresent()) {
try {
@ -145,9 +137,9 @@ public class MainActivity extends AppCompatActivity {
}
}));
context.getGlobalObject().set(context, JavaScriptString.create("run"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
context.getGlobalObject().set(context, JavaScriptValue.create("run"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
public Optional<JavaScriptValue> callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
long sm = System.currentTimeMillis();
Optional<JavaScriptString> s = javaScriptValues[0].toString(finalContext);
if (s.isPresent()) {
@ -157,16 +149,16 @@ public class MainActivity extends AppCompatActivity {
}
}));
context.getGlobalObject().set(context, JavaScriptString.create("read"), JavaScriptJavaCallbackFunctionObject.create(context, "read", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
context.getGlobalObject().set(context, JavaScriptValue.create("read"), JavaScriptJavaCallbackFunctionObject.create(context, "read", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
public Optional<JavaScriptValue> callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) {
Optional<JavaScriptString> s = javaScriptValues[0].toString(finalContext);
if (s.isPresent()) {
FileReader in = null;
try {
byte[] chars = Files.readAllBytes(Paths.get(s.get().toJavaString()));
String fileContent = new String(chars);
return Optional.of(JavaScriptString.create(fileContent));
return Optional.of(JavaScriptValue.create(fileContent));
}
catch (Exception ex) {
return Optional.empty();
@ -196,116 +188,6 @@ public class MainActivity extends AppCompatActivity {
}).start();
}
public void runExample()
{
new Thread(() -> {
Looper.prepare();
Handler handler = new Handler(Looper.myLooper());
Globals.initializeGlobals();
VMInstance vmInstance = VMInstance.create(Optional.empty(), Optional.empty());
Context context = Context.create(vmInstance);
context.getGlobalObject().set(context, JavaScriptString.create("print"), JavaScriptJavaCallbackFunctionObject.create(context, "", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) {
System.out.println(arguments[0].toString(context).get().toJavaString());
return Optional.empty();
}
}));
context.getGlobalObject().set(context, JavaScriptString.create("end"), JavaScriptJavaCallbackFunctionObject.create(context, "", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() {
@Override
public Optional<JavaScriptValue> callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) {
Looper.myLooper().quitSafely();
return Optional.empty();
}
}));
MultiThreadExecutor executor = new MultiThreadExecutor(vmInstance, new MultiThreadExecutor.WorkerThreadEndNotifier() {
@Override
public void notify(MultiThreadExecutor executor, MultiThreadExecutor.ExecutorInstance instance) {
handler.post(new Runnable() {
@Override
public void run() {
executor.pumpEventsFromThreadIfNeeds();
}
});
}
});
Bridge.register(context, "HTTP", "get", new Bridge.Adapter() {
@Override
public Optional<JavaScriptValue> callback(Context context, Optional<JavaScriptValue> data) {
String url = "";
if (data.isPresent()) {
Optional<JavaScriptString> mayBeString = data.get().toString(context);
if (mayBeString.isPresent()) {
url = mayBeString.get().toJavaString();
}
}
final String finalURL = url;
MultiThreadExecutor.ExecutorInstance instance = executor.startWorker(context, new MultiThreadExecutor.Executor() {
@Override
public MultiThreadExecutor.ResultBuilderContext run() {
try {
HttpURLConnection connection = (HttpURLConnection)new URL(finalURL).openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return new MultiThreadExecutor.ResultBuilderContext(true, response.toString());
} else {
return new MultiThreadExecutor.ResultBuilderContext(false, "error HTTP return code:" + responseCode);
}
} catch (IOException e) {
return new MultiThreadExecutor.ResultBuilderContext(false, e.toString());
}
}
}, new MultiThreadExecutor.ResultBuilder() {
@Override
public JavaScriptValue build(Context scriptContext, MultiThreadExecutor.ResultBuilderContext builderContext) {
return JavaScriptString.create((String)builderContext.data());
}
});
return Optional.of(instance.promise());
}
});
Evaluator.evalScript(context, "" +
"let promise1 = HTTP.get('https://httpbin.org/get');" +
"let promise2 = HTTP.get('http://google.com');" +
"Promise.allSettled([promise1, promise2]).then(function(v) {" +
"print(JSON.stringify(v));" +
"print('http all end!');" +
"end();" +
"});", "", false);
Looper.loop();
Looper.myLooper().quit();
context = null;
vmInstance = null;
Memory.gc();
Memory.gc();
Memory.gc();
Memory.gc();
Memory.gc();
Globals.finalizeGlobals();
}).start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -323,11 +205,11 @@ public class MainActivity extends AppCompatActivity {
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
(new Handler()).postDelayed(new Runnable() {
@Override
public void onClick(View v) {
runExample();
public void run() {
findViewById(R.id.button).callOnClick();
}
});
}, 3000);
}
}

View file

@ -11,12 +11,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="run"/>
<Button
android:id="@+id/button2"
android:layout_toRightOf="@id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="mt example"/>
<TextView
android:layout_below="@+id/button"
android:layout_width="match_parent"

View file

@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.10.1' apply false
id 'com.android.library' version '8.10.1' apply false
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
}

View file

@ -1,29 +1,26 @@
plugins {
id 'com.android.library'
id 'jacoco'
id 'maven-publish'
}
ext {
force64Option = System.getProperty("ESCARGOT_BUILD_64BIT_FORCE_LARGE", "ON")
pthreadKeyOption = System.getProperty("ESCARGOT_BUILD_TLS_ACCESS_BY_PTHREAD_KEY", "OFF")
force64Option = System.getProperty("ESCARGOT_BUILD_64BIT_FORCE_LARGE", "OFF")
}
android {
namespace 'com.samsung.lwe.escargot'
compileSdk 36
ndkVersion '28.1.13356709'
compileSdk 33
defaultConfig {
minSdk 28
targetSdk 36
targetSdk 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
externalNativeBuild {
cmake {
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON", "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DESCARGOT_HOST=android", "-DESCARGOT_OUTPUT=static_lib", "-DENABLE_SHELL=OFF",
"-DESCARGOT_BUILD_64BIT_FORCE_LARGE="+project.ext.force64Option, "-DESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY="+project.ext.pthreadKeyOption
arguments "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DESCARGOT_HOST=android", "-DESCARGOT_OUTPUT=static_lib", "-DENABLE_SHELL=OFF",
"-DESCARGOT_BUILD_64BIT_FORCE_LARGE="+project.ext.force64Option
}
}
@ -40,6 +37,7 @@ android {
debug {
testCoverageEnabled true
debuggable = true
jniDebuggable = true
ndk {
debuggable = true
@ -57,6 +55,7 @@ android {
releaseShell {
initWith(buildTypes.release)
debuggable = true
jniDebuggable = true
ndk {
debuggable = true
@ -79,42 +78,16 @@ android {
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.18.1"
}
}
ndkVersion '27.0.12077973'
ndkVersion '25.2.9519653'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
publishing {
singleVariant("release") {
// if you don't want sources/javadoc, remove these lines
withSourcesJar()
withJavadocJar()
}
}
}
publishing {
publications {
release(MavenPublication) {
afterEvaluate {
from components.release
}
artifactId "escargot-android"
groupId "com.samsung.lwe.escargot"
version "X.X.X.20XXXXXX.X.XXXXXXXX"
}
}
repositories {
maven {
url "/XXXXXX/android/releases/"
}
}
}
def dirForNativeNoNDK = project.layout.buildDirectory.get().dir("native_nondk")
@ -128,9 +101,7 @@ task buildCMakeNativeNoNDK(type: Exec) {
dependsOn createNativeNoNDK
workingDir dirForNativeNoNDK
if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
commandLine "/usr/bin/env", "cmake", "-DESCARGOT_HOST=linux", "-DESCARGOT_ARCH=x64", "-DESCARGOT_OUTPUT=static_lib",
"-DESCARGOT_BUILD_64BIT_FORCE_LARGE="+project.ext.force64Option,
"-DUNDER_NDK=OFF", srcForNativeNoNDK.absolutePath
commandLine "/usr/bin/env", "cmake", "-DESCARGOT_HOST=linux", "-DESCARGOT_ARCH=x64", "-DESCARGOT_OUTPUT=static_lib", "-DUNDER_NDK=OFF", srcForNativeNoNDK.absolutePath
} else if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
var javaHome = new ByteArrayOutputStream().withStream { os ->
exec {
@ -140,18 +111,8 @@ task buildCMakeNativeNoNDK(type: Exec) {
}
os.toString().trim()
}
var icu4cPath = new ByteArrayOutputStream().withStream { os ->
exec {
commandLine "sh", "-c", "brew --prefix icu4c"
standardOutput = os
}
os.toString().trim()
}
var pkgConfigPath = icu4cPath + "/lib/pkgconfig"
environment("PKG_CONFIG_PATH", pkgConfigPath)
commandLine "/usr/bin/env", "cmake", "-DESCARGOT_HOST=darwin", "-DESCARGOT_ARCH=x64", "-DESCARGOT_OUTPUT=static_lib", "-DUNDER_NDK=OFF",
"-DESCARGOT_BUILD_64BIT_FORCE_LARGE="+project.ext.force64Option,
"-DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF",
environment("PKG_CONFIG_PATH", "/usr/local/opt/icu4c/lib/pkgconfig")
commandLine "/usr/bin/env", "cmake", "-DESCARGOT_HOST=darwin", "-DESCARGOT_ARCH=x64", "-DESCARGOT_OUTPUT=static_lib", "-DUNDER_NDK=OFF", "-DESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN=OFF",
"-DJAVA_HOME=" + javaHome, "-DJAVA_INCLUDE_PATH=" + javaHome + "/include",
"-DJAVA_INCLUDE_PATH2=" + javaHome + "/include/darwin", "-DJAVA_AWT_INCLUDE_PATH=" + javaHome + "/include",
srcForNativeNoNDK.absolutePath
@ -168,9 +129,10 @@ task buildGMakeNativeNoNDK(type: Exec) {
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
reports {
xml.required = true
html.required = true
xml.enabled = true
html.enabled = true
}
def mainSrc = "${project.projectDir}/src/main/java"
sourceDirectories.setFrom(files([mainSrc]))
@ -197,13 +159,13 @@ project.afterEvaluate {
}
task clearHostJar(type: Delete) {
delete 'build/libs/escargot.jar'
delete 'build/outputs/escargot.jar'
}
task bundleHostJar(type: Jar) {
dependsOn buildGMakeNativeNoNDK
dependsOn assemble
from(zipTree('build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar'))
from(zipTree('build/intermediates/aar_main_jar/debug/classes.jar'))
from(dirForNativeNoNDK.asFile.toString() + "/libescargot-jni.so")
from(dirForNativeNoNDK.asFile.toString() + "/libescargot-jni.dylib")
rename("libescargot-jni.dylib", "libescargot-jni.so")
@ -217,6 +179,7 @@ task sourcesJar(type: Jar) {
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all { variant ->
if (variant.name == 'release') {
owner.classpath += variant.javaCompileProvider.get().classpath

View file

@ -1,2 +1 @@
-keep class com.samsung.lwe.escargot.* { *; }
-keep enum com.samsung.lwe.escargot.* { *; }

View file

@ -21,4 +21,3 @@
#-renamesourcefileattribute SourceFile
-keep class com.samsung.lwe.escargot.* { *; }
-keep enum com.samsung.lwe.escargot.* { *; }

View file

@ -5,8 +5,7 @@ project(escargot-jni)
option(UNDER_NDK "Build under the Android NDK" ON)
option(ENABLE_SHELL "Enable shell" OFF)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions -Wno-conversion-null -fPIC -ftls-model=local-dynamic ")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -ftls-model=local-dynamic ")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions")
if (NOT UNDER_NDK)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -g3")
@ -24,9 +23,7 @@ if (ENABLE_SHELL)
endif ()
ADD_SUBDIRECTORY (${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../ escargot)
FILE (GLOB_RECURSE JNI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
ADD_LIBRARY (escargot-jni SHARED ${JNI_SRC})
ADD_LIBRARY (escargot-jni SHARED escargot.cpp)
SET(LOG_LIBRARY "")
if (NOT UNDER_NDK)
ADD_DEFINITIONS(-DNDEBUG)
@ -34,10 +31,7 @@ endif ()
if (UNDER_NDK)
FIND_LIBRARY(LOG_LIBRARY log)
# enable 16KB page size (require version of Android NDK >= 27)
TARGET_LINK_OPTIONS(escargot PRIVATE "-Wl,-z,max-page-size=16384")
TARGET_LINK_OPTIONS(escargot-jni PRIVATE "-Wl,-z,max-page-size=16384")
else ()
else (UNDER_NDK)
FIND_PACKAGE(JNI REQUIRED)
INCLUDE_DIRECTORIES(${JNI_INCLUDE_DIRS})
endif ()
@ -46,14 +40,15 @@ TARGET_LINK_LIBRARIES (escargot-jni PRIVATE escargot ${LOG_LIBRARY})
if (ENABLE_SHELL)
SET(CMAKE_EXE_LINKER_FLAGS -Wl,-export-dynamic) # export symbol of Shell.cpp
ADD_COMPILE_OPTIONS(-DNDEBUG -g3 -DESCARGOT_ENABLE_TEST -fPIC)
ADD_COMPILE_OPTIONS(-DNDEBUG -g3 -DESCARGOT_ENABLE_TEST)
ADD_LINK_OPTIONS(-static-libstdc++)
ADD_EXECUTABLE(escargot-shell ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/shell/Shell.cpp)
TARGET_INCLUDE_DIRECTORIES(escargot-shell PRIVATE ADD_SUBDIRECTORY
(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../third_party/GCutil/include)
(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../third_party/GCutil/)
(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../third_party/GCutil/bdwgc/include)
(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src))
TARGET_LINK_LIBRARIES (escargot-shell PRIVATE escargot ${LOG_LIBRARY})
ADD_EXECUTABLE(test-data-runner ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../tools/test/test-data-runner/test-data-runner.cpp)
TARGET_COMPILE_OPTIONS(test-data-runner PRIVATE -std=c++11 -fPIC)
endif ()
TARGET_COMPILE_OPTIONS(test-data-runner PRIVATE -std=c++11)
endif ()

View file

@ -1,350 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
JavaVM* g_jvm;
size_t g_nonPointerValueLast = reinterpret_cast<size_t>(ValueRef::createUndefined());
thread_local std::vector<ExecutionStateRef*> ExecutionStateRefTracker::g_lastExecutionStateVector;
jobject createJavaValueObject(JNIEnv* env, jclass clazz, ValueRef* value)
{
jobject valueObject;
if (!value->isStoredInHeap()) {
valueObject = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "(JZ)V"), reinterpret_cast<jlong>(value), jboolean(false));
} else {
PersistentRefHolder<ValueRef>* pRef = new PersistentRefHolder<ValueRef>(value);
jlong ptr = reinterpret_cast<size_t>(pRef);
valueObject = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "(J)V"), ptr);
}
return valueObject;
}
jobject createJavaValueObject(JNIEnv* env, const char* className, ValueRef* value)
{
return createJavaValueObject(env, env->FindClass(className), value);
}
ValueRef* unwrapValueRefFromValue(JNIEnv* env, jclass clazz, jobject object)
{
auto ptr = env->GetLongField(object, env->GetFieldID(clazz, "m_nativePointer", "J"));
if (static_cast<size_t>(ptr) <= g_nonPointerValueLast || (static_cast<size_t>(ptr) & 1)) {
return reinterpret_cast<ValueRef*>(ptr);
} else {
PersistentRefHolder<ValueRef>* ref = reinterpret_cast<PersistentRefHolder<ValueRef>*>(ptr);
return ref->get();
}
}
jobject createJavaObjectFromValue(JNIEnv* env, ValueRef* value)
{
if (!value->isStoredInHeap() || value->isNumber()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptValue", value);
} else if (value->isString()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptString", value);
} else if (value->isSymbol()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptSymbol", value);
} else if (value->isBigInt()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptBigInt", value);
} else if (value->isObject()) {
if (value->isArrayObject()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptArrayObject", value);
} else if (value->isGlobalObject()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptGlobalObject", value);
} else if (value->isFunctionObject()) {
if (value->asFunctionObject()->extraData()) {
ScriptObjectExtraData* data = reinterpret_cast<ScriptObjectExtraData*>(value->asFunctionObject()->extraData());
if (data->implementSideData) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject", value);
}
}
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptFunctionObject", value);
} else if (value->isPromiseObject()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptPromiseObject", value);
} else if (value->isErrorObject()) {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptErrorObject", value);
} else {
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptObject", value);
}
} else {
abort();
}
}
jobject createJavaObject(JNIEnv* env, VMInstanceRef* value)
{
PersistentRefHolder<VMInstanceRef>* pRef = new PersistentRefHolder<VMInstanceRef>(value);
jlong ptr = reinterpret_cast<size_t>(pRef);
jclass clazz = env->FindClass("com/samsung/lwe/escargot/VMInstance");
return env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "(J)V"), ptr);
}
jobject createJavaObject(JNIEnv* env, ContextRef* value)
{
PersistentRefHolder<ContextRef>* pRef = new PersistentRefHolder<ContextRef>(value);
jlong ptr = reinterpret_cast<size_t>(pRef);
jclass clazz = env->FindClass("com/samsung/lwe/escargot/Context");
return env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "(J)V"), ptr);
}
OptionalRef<JNIEnv> fetchJNIEnvFromCallback()
{
JNIEnv* env = nullptr;
if (g_jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) == JNI_EDETACHED) {
#if defined(_JAVASOFT_JNI_H_) // oraclejdk or openjdk
if (g_jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), NULL) != 0) {
#else
if (g_jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&env), NULL) != 0) {
#endif
// give up
return nullptr;
}
}
return env;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Escargot_init(JNIEnv* env, jclass clazz)
{
thread_local static bool inited = false;
if (!inited) {
if (!g_jvm) {
env->GetJavaVM(&g_jvm);
}
inited = true;
}
}
std::string fetchStringFromJavaOptionalString(JNIEnv *env, jobject optional)
{
auto classOptionalString = env->GetObjectClass(optional);
auto methodIsPresent = env->GetMethodID(classOptionalString, "isPresent", "()Z");
if (env->CallBooleanMethod(optional, methodIsPresent)) {
auto methodGet = env->GetMethodID(classOptionalString, "get", "()Ljava/lang/Object;");
jboolean isSucceed;
jstring value = static_cast<jstring>(env->CallObjectMethod(optional, methodGet));
const char* str = env->GetStringUTFChars(
value, &isSucceed);
auto length = env->GetStringUTFLength(value);
auto ret = std::string(str, length);
env->ReleaseStringUTFChars(value, str);
return ret;
}
return std::string();
}
StringRef* createJSStringFromJava(JNIEnv* env, jstring str)
{
if (!str) {
return StringRef::emptyString();
}
jboolean isSucceed;
const char* cString = env->GetStringUTFChars(str, &isSucceed);
StringRef* code = StringRef::createFromUTF8(cString, env->GetStringUTFLength(str));
env->ReleaseStringUTFChars(str, cString);
return code;
}
std::string createStringFromJava(JNIEnv* env, jstring str)
{
if (!str) {
return std::string();
}
jboolean isSucceed;
const char* cString = env->GetStringUTFChars(str, &isSucceed);
std::string ret = std::string(cString, env->GetStringUTFLength(str));
env->ReleaseStringUTFChars(str, cString);
return ret;
}
jstring createJavaStringFromJS(JNIEnv* env, StringRef* string)
{
std::basic_string<uint16_t> buf;
auto bad = string->stringBufferAccessData();
buf.reserve(bad.length);
for (size_t i = 0; i < bad.length ; i ++) {
buf.push_back(bad.charAt(i));
}
return env->NewString(buf.data(), buf.length());
}
void throwJavaRuntimeException(ExecutionStateRef* state)
{
state->throwException(ErrorObjectRef::create(state, ErrorObjectRef::None, StringRef::createFromASCII("Java runtime exception")));
}
bool hasJavaScriptRuntimeExceptionOnEnv(JNIEnv* env)
{
if (env->ExceptionCheck()) {
jthrowable exception = env->ExceptionOccurred();
env->ExceptionClear();
bool ret = env->IsInstanceOf(exception, env->FindClass("com/samsung/lwe/escargot/internal/JavaScriptRuntimeException"));
env->Throw(exception);
return ret;
}
return false;
}
OptionalRef<ValueRef> extractExceptionFromEnv(JNIEnv* env)
{
if (env->ExceptionCheck()) {
jthrowable exception = env->ExceptionOccurred();
env->ExceptionClear();
bool ret = env->IsInstanceOf(exception, env->FindClass("com/samsung/lwe/escargot/internal/JavaScriptRuntimeException"));
if (ret) {
jclass clz = env->FindClass("com/samsung/lwe/escargot/internal/JavaScriptRuntimeException");
jobject jv = env->CallObjectMethod(exception, env->GetMethodID(clz, "exception", "()Lcom/samsung/lwe/escargot/JavaScriptValue;"));
ValueRef* v = unwrapValueRefFromValue(env, env->GetObjectClass(jv), jv);
return v;
} else {
env->Throw(exception);
}
}
return nullptr;
}
bool hasJavaExcpetion(JNIEnv* env)
{
if (env->ExceptionCheck() && !hasJavaScriptRuntimeExceptionOnEnv(env)) {
return true;
}
return false;
}
jobject storeExceptionOnContextAndReturnsIt(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult)
{
if (hasJavaExcpetion(env)) {
return nullptr;
}
auto exceptionOnEnv = extractExceptionFromEnv(env);
jclass optionalClazz = env->FindClass("java/util/Optional");
// store exception to context
auto fieldId = env->GetFieldID(env->GetObjectClass(contextObject), "m_lastThrownException", "Ljava/util/Optional;");
ValueRef* exception = exceptionOnEnv ? exceptionOnEnv.get() : evaluatorResult.error.value();
auto fieldValue = env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
createJavaObjectFromValue(env, exception));
env->SetObjectField(contextObject, fieldId, fieldValue);
return env->CallStaticObjectMethod(optionalClazz, env->GetStaticMethodID(optionalClazz, "empty",
"()Ljava/util/Optional;"));
}
jobject createOptionalValueFromEvaluatorJavaScriptValueResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult)
{
if (hasJavaExcpetion(env)) {
return nullptr;
}
if (evaluatorResult.isSuccessful()) {
jclass optionalClazz = env->FindClass("java/util/Optional");
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
createJavaObjectFromValue(env, evaluatorResult.result));
}
return storeExceptionOnContextAndReturnsIt(env, contextObject, context, evaluatorResult);
}
jobject createOptionalValueFromEvaluatorBooleanResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult)
{
if (hasJavaExcpetion(env)) {
return nullptr;
}
if (evaluatorResult.isSuccessful()) {
jclass optionalClazz = env->FindClass("java/util/Optional");
auto booleanClazz = env->FindClass("java/lang/Boolean");
auto valueOfMethodId = env->GetStaticMethodID(booleanClazz, "valueOf", "(Z)Ljava/lang/Boolean;");
auto javaBoolean = env->CallStaticObjectMethod(booleanClazz, valueOfMethodId, (jboolean)evaluatorResult.result->asBoolean());
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
javaBoolean);
}
return storeExceptionOnContextAndReturnsIt(env, contextObject, context, evaluatorResult);
}
jobject createOptionalValueFromEvaluatorIntegerResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult)
{
if (hasJavaExcpetion(env)) {
return nullptr;
}
if (evaluatorResult.isSuccessful()) {
jclass optionalClazz = env->FindClass("java/util/Optional");
auto containerClass = env->FindClass("java/lang/Integer");
auto valueOfMethodId = env->GetStaticMethodID(containerClass, "valueOf", "(I)Ljava/lang/Integer;");
auto javaValue = env->CallStaticObjectMethod(containerClass, valueOfMethodId, (jint)evaluatorResult.result->asInt32());
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
javaValue);
}
return storeExceptionOnContextAndReturnsIt(env, contextObject, context, evaluatorResult);
}
jobject createOptionalValueFromEvaluatorDoubleResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult)
{
if (hasJavaExcpetion(env)) {
return nullptr;
}
if (evaluatorResult.isSuccessful()) {
jclass optionalClazz = env->FindClass("java/util/Optional");
auto containerClass = env->FindClass("java/lang/Double");
auto valueOfMethodId = env->GetStaticMethodID(containerClass, "valueOf", "(D)Ljava/lang/Double;");
auto javaValue = env->CallStaticObjectMethod(containerClass, valueOfMethodId, (jdouble)evaluatorResult.result->asNumber());
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
javaValue);
}
return storeExceptionOnContextAndReturnsIt(env, contextObject, context, evaluatorResult);
}
ScriptObjectExtraData* ensureScriptObjectExtraData(ObjectRef* ref)
{
ScriptObjectExtraData* data = reinterpret_cast<ScriptObjectExtraData*>(ref->extraData());
if (!data) {
data = new ScriptObjectExtraData;
ref->setExtraData(data);
Memory::gcRegisterFinalizer(ref, [](void* self, void* data) {
ScriptObjectExtraData* extraData = reinterpret_cast<ScriptObjectExtraData*>(reinterpret_cast<ObjectRef*>(self)->extraData());
auto env = fetchJNIEnvFromCallback();
if (env) {
if (extraData->implementSideData) {
env->DeleteGlobalRef(extraData->implementSideData);
extraData->implementSideData = nullptr;
}
if (extraData->userData) {
env->DeleteGlobalRef(extraData->userData);
extraData->userData = nullptr;
}
}
}, nullptr);
}
return data;
}

View file

@ -1,185 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef ESCARGOT_ANDROID_ESCARGOTJNI_H
#define ESCARGOT_ANDROID_ESCARGOTJNI_H
#include <jni.h>
#include <EscargotPublic.h>
#include <vector>
#include <set>
#include <cassert>
using namespace Escargot;
#if defined(ANDROID)
#include <android/log.h>
#define LOG_TAG "Escargot"
#define LOGUNK(...) __android_log_print(ANDROID_LOG_UNKNOWN,LOG_TAG,__VA_ARGS__)
#define LOGDEF(...) __android_log_print(ANDROID_LOG_DEFAULT,LOG_TAG,__VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_FATAL_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGS(...) __android_log_print(ANDROID_SILENT_ERROR,LOG_TAG,__VA_ARGS__)
#else
#define LOGUNK(...) fprintf(stdout,__VA_ARGS__)
#define LOGDEF(...) fprintf(stdout,__VA_ARGS__)
#define LOGV(...) fprintf(stdout,__VA_ARGS__)
#define LOGD(...) fprintf(stdout,__VA_ARGS__)
#define LOGI(...) fprintf(stdout,__VA_ARGS__)
#define LOGW(...) fprintf(stdout,__VA_ARGS__)
#define LOGE(...) fprintf(stderr,__VA_ARGS__)
#define LOGF(...) fprintf(stderr,__VA_ARGS__)
#define LOGS(...) fprintf(stderr,__VA_ARGS__)
#endif
#define THROW_NPE_RETURN_NULL(param, paramType) \
if (env->ExceptionCheck()) { \
return 0; \
} \
if (!param) { \
env->ThrowNew(env->FindClass("java/lang/NullPointerException"), paramType" cannot be null"); \
return 0; \
}
#define THROW_NPE_RETURN_VOID(param, paramType) \
if (env->ExceptionCheck()) { \
return; \
} \
if (!param) { \
env->ThrowNew(env->FindClass("java/lang/NullPointerException"), paramType" cannot be null"); \
return; \
}
#define THROW_CAST_EXCEPTION_IF_NEEDS(param, value, typeName) \
if (env->ExceptionCheck()) { \
return NULL; \
} \
if (!value->is##typeName()) { \
env->ThrowNew(env->FindClass("java/lang/ClassCastException"), "Can not cast to " #typeName); \
return NULL; \
}
extern JavaVM* g_jvm;
extern size_t g_nonPointerValueLast;
jobject createJavaValueObject(JNIEnv* env, jclass clazz, ValueRef* value);
jobject createJavaValueObject(JNIEnv* env, const char* className, ValueRef* value);
jobject createJavaObject(JNIEnv* env, VMInstanceRef* value);
jobject createJavaObject(JNIEnv* env, ContextRef* value);
ValueRef* unwrapValueRefFromValue(JNIEnv* env, jclass clazz, jobject object);
jobject createJavaObjectFromValue(JNIEnv* env, ValueRef* value);
ValueRef* unwrapValueRefFromValue(JNIEnv* env, jclass clazz, jobject object);
OptionalRef<JNIEnv> fetchJNIEnvFromCallback();
std::string fetchStringFromJavaOptionalString(JNIEnv *env, jobject optional);
StringRef* createJSStringFromJava(JNIEnv* env, jstring str);
std::string createStringFromJava(JNIEnv* env, jstring str);
jstring createJavaStringFromJS(JNIEnv* env, StringRef* string);
void throwJavaRuntimeException(ExecutionStateRef* state);
OptionalRef<ValueRef> extractExceptionFromEnv(JNIEnv* env);
jobject storeExceptionOnContextAndReturnsIt(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult);
jobject createOptionalValueFromEvaluatorJavaScriptValueResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult);
jobject createOptionalValueFromEvaluatorBooleanResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult);
jobject createOptionalValueFromEvaluatorIntegerResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult);
jobject createOptionalValueFromEvaluatorDoubleResult(JNIEnv* env, jobject contextObject, ContextRef* context, Evaluator::EvaluatorResult& evaluatorResult);
struct ScriptObjectExtraData {
jobject userData;
jobject implementSideData;
ScriptObjectExtraData()
: userData(nullptr)
, implementSideData(nullptr)
{
}
void* operator new(size_t t)
{
return Memory::gcMallocAtomic(sizeof(ScriptObjectExtraData));
}
};
ScriptObjectExtraData* ensureScriptObjectExtraData(ObjectRef* ref);
template<typename T>
jobject nativeOptionalValueIntoJavaOptionalValue(JNIEnv* env, OptionalRef<T> ref)
{
if (env->ExceptionCheck()) {
return nullptr;
}
jclass optionalClazz = env->FindClass("java/util/Optional");
if (ref) {
jmethodID ctorMethod = env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;");
return env->CallStaticObjectMethod(optionalClazz, ctorMethod, createJavaObjectFromValue(env, ref.value()));
}
return env->CallStaticObjectMethod(optionalClazz, env->GetStaticMethodID(optionalClazz, "empty",
"()Ljava/util/Optional;"));
}
template<typename NativeType>
PersistentRefHolder<NativeType>* getPersistentPointerFromJava(JNIEnv *env, jclass clazz, jobject object)
{
auto ptr = env->GetLongField(object, env->GetFieldID(clazz, "m_nativePointer", "J"));
PersistentRefHolder<NativeType>* pVMRef = reinterpret_cast<PersistentRefHolder<NativeType>*>(ptr);
return pVMRef;
}
class ExecutionStateRefTracker {
public:
ExecutionStateRefTracker(ExecutionStateRef* newValue)
{
g_lastExecutionStateVector.push_back(newValue);
}
~ExecutionStateRefTracker()
{
g_lastExecutionStateVector.pop_back();
}
private:
friend class ScriptEvaluator;
static thread_local std::vector<ExecutionStateRef*> g_lastExecutionStateVector;
};
class ScriptEvaluator {
public:
template <typename... Args, typename F>
static Evaluator::EvaluatorResult execute(ContextRef* ctx, F&& closure, Args... args)
{
typedef ValueRef* (*Closure)(ExecutionStateRef * state, Args...);
if (ExecutionStateRefTracker::g_lastExecutionStateVector.size()) {
return Evaluator::execute(ExecutionStateRefTracker::g_lastExecutionStateVector.back(), [](ExecutionStateRef * state, Closure closure, Args... args) -> ValueRef* {
ExecutionStateRefTracker tracker(state);
return closure(state, args...);
}, Closure(closure), args...);
} else {
return Evaluator::execute(ctx, [](ExecutionStateRef * state, Closure closure, Args... args) -> ValueRef* {
ExecutionStateRefTracker tracker(state);
return closure(state, args...);
}, Closure(closure), args...);
}
}
};
#endif //ESCARGOT_ANDROID_ESCARGOTJNI_H

View file

@ -1,74 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptArrayObject_create(JNIEnv* env, jclass clazz,
jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state) -> ValueRef* {
return ArrayObjectRef::create(state);
});
assert(evaluatorResult.isSuccessful());
return createJavaObjectFromValue(env, evaluatorResult.result->asArrayObject());
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_samsung_lwe_escargot_JavaScriptArrayObject_length(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ArrayObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asArrayObject();
int64_t length = 0;
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ArrayObjectRef* thisValueRef, int64_t* pLength) -> ValueRef* {
*pLength = static_cast<int64_t>(thisValueRef->length(state));
return ValueRef::createUndefined();
}, thisValueRef, &length);
return length;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_JavaScriptArrayObject_setLength(JNIEnv* env, jobject thiz,
jobject context, jlong newLength)
{
THROW_NPE_RETURN_VOID(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ArrayObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asArrayObject();
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ArrayObjectRef* thisValueRef, jlong pLength) -> ValueRef* {
if (pLength >= 0) {
thisValueRef->setLength(state, static_cast<uint64_t>(pLength));
} else {
thisValueRef->set(state, AtomicStringRef::create(state->context(), "length")->string(), ValueRef::create(pLength));
}
return ValueRef::createUndefined();
}, thisValueRef, newLength);
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_create__I(JNIEnv* env, jclass clazz, jint num)
{
return createJavaValueObject(env, clazz, BigIntRef::create(static_cast<int64_t>(num)));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_create__J(JNIEnv* env, jclass clazz, jlong num)
{
return createJavaValueObject(env, clazz, BigIntRef::create(static_cast<int64_t>(num)));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_create__Ljava_lang_String_2I(JNIEnv* env,
jclass clazz,
jstring numString,
jint radix)
{
return createJavaValueObject(env, clazz,
BigIntRef::create(createJSStringFromJava(env, numString), radix));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_create__Lcom_samsung_lwe_escargot_JavaScriptString_2I(
JNIEnv* env, jclass clazz, jobject numString, jint radix)
{
if (numString) {
return createJavaValueObject(env, clazz,
BigIntRef::create(unwrapValueRefFromValue(env, env->GetObjectClass(
numString), numString)->asString(), radix));
} else {
return createJavaValueObject(env, clazz, BigIntRef::create(static_cast<int64_t>(0)));
}
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_toString(JNIEnv* env, jobject thiz, jint radix)
{
return createJavaObjectFromValue(env, unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asBigInt()->toString(radix));
}
extern "C"
JNIEXPORT jdouble JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_toNumber(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asBigInt()->toNumber();
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_samsung_lwe_escargot_JavaScriptBigInt_toInt64(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asBigInt()->toInt64();
}

View file

@ -1,153 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_Bridge_register(JNIEnv* env, jclass clazz, jobject context,
jstring objectName, jstring propertyName,
jobject adapter)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(adapter, "Adapter");
auto contextPtr = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context),
context);
auto jsObjectName = createJSStringFromJava(env, objectName);
auto jsPropertyName = createJSStringFromJava(env, propertyName);
if (!jsObjectName->length() || !jsPropertyName->length()) {
return 0;
}
adapter = env->NewGlobalRef(adapter);
auto evalResult = ScriptEvaluator::execute(contextPtr->get(),
[](ExecutionStateRef* state, JNIEnv* env, jobject adapter,
StringRef* jsObjectName,
StringRef* jsPropertyName) -> ValueRef* {
auto globalObject = state->context()->globalObject();
ObjectRef* targetObject;
ValueRef* willBeTargetObject = globalObject->getOwnProperty(
state, jsObjectName);
if (willBeTargetObject->isObject()) {
targetObject = willBeTargetObject->asObject();
} else {
targetObject = ObjectRef::create(state);
globalObject->defineDataProperty(state,
jsObjectName,
targetObject,
true, true, true);
}
FunctionObjectRef::NativeFunctionInfo info(
AtomicStringRef::create(state->context(), jsPropertyName),
[](ExecutionStateRef* state,
ValueRef* thisValue, size_t argc,
ValueRef** argv,
bool isConstructorCall) -> ValueRef* {
ExecutionStateRefTracker tracker(state);
FunctionObjectRef* callee = state->resolveCallee().get();
jobject jo = ensureScriptObjectExtraData(
reinterpret_cast<FunctionObjectRef*>(callee))->implementSideData;
auto env = fetchJNIEnvFromCallback();
if (!env) {
// give up
LOGE("could not fetch env from callback");
return ValueRef::createUndefined();
}
if (env->ExceptionCheck()) {
throwJavaRuntimeException(state);
return ValueRef::createUndefined();
}
env->PushLocalFrame(32);
jobject callbackArg;
jclass optionalClazz = env->FindClass(
"java/util/Optional");
if (argc) {
callbackArg = env->CallStaticObjectMethod(
optionalClazz,
env->GetStaticMethodID(
optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
createJavaObjectFromValue(env.get(), argv[0]));
} else {
callbackArg = env->CallStaticObjectMethod(
optionalClazz,
env->GetStaticMethodID(
optionalClazz, "empty",
"()Ljava/util/Optional;"));
}
auto javaReturnValue = env->CallObjectMethod(
jo,
env->GetMethodID(
env->GetObjectClass(jo),
"callback",
"(Lcom/samsung/lwe/escargot/Context;Ljava/util/Optional;)Ljava/util/Optional;"),
createJavaObject(env.get(), callee->context()),
callbackArg);
if (env->ExceptionCheck()) {
env->PopLocalFrame(NULL);
throwJavaRuntimeException(state);
return ValueRef::createUndefined();
}
auto methodIsPresent = env->GetMethodID(
optionalClazz, "isPresent", "()Z");
ValueRef* nativeReturnValue = ValueRef::createUndefined();
if (javaReturnValue && env->CallBooleanMethod(javaReturnValue,
methodIsPresent)) {
auto methodGet = env->GetMethodID(
optionalClazz, "get",
"()Ljava/lang/Object;");
jobject value = env->CallObjectMethod(
javaReturnValue, methodGet);
nativeReturnValue = unwrapValueRefFromValue(
env.get(),
env->GetObjectClass(value),
value);
}
env->PopLocalFrame(NULL);
return nativeReturnValue;
}, 1, true, false);
FunctionObjectRef* callback = FunctionObjectRef::create(
state, info);
targetObject->defineDataProperty(state, jsPropertyName,
callback, true, true,
true);
return callback;
}, env, adapter, jsObjectName, jsPropertyName);
if (evalResult.isSuccessful()) {
FunctionObjectRef* callback = evalResult.result->asFunctionObject();
ensureScriptObjectExtraData(callback)->implementSideData = adapter;
} else {
env->DeleteGlobalRef(adapter);
}
return evalResult.isSuccessful();
}

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_Context_create(JNIEnv* env, jclass clazz, jobject vmInstance)
{
THROW_NPE_RETURN_NULL(vmInstance, "VMInstance");
auto vmPtr = getPersistentPointerFromJava<VMInstanceRef>(env, env->GetObjectClass(vmInstance),
vmInstance);
auto contextRef = ContextRef::create(vmPtr->get());
return createJavaObject(env, contextRef.get());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_Context_getGlobalObject(JNIEnv* env, jobject thiz)
{
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(thiz), thiz);
return createJavaObjectFromValue(env, contextRef->get()->globalObject());
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_Context_throwException(JNIEnv* env, jobject thiz, jobject exception)
{
THROW_NPE_RETURN_NULL(exception, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(thiz), thiz);
if (contextRef->get()->canThrowException()) {
ValueRef* exceptionRef = unwrapValueRefFromValue(env, env->GetObjectClass(exception), exception);
if (exceptionRef->isErrorObject()) {
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* exceptionRef) -> ValueRef* {
exceptionRef->asErrorObject()->updateStackTraceData(state);
return ValueRef::createUndefined();
}, exceptionRef);
}
jclass clz = env->FindClass("com/samsung/lwe/escargot/internal/JavaScriptRuntimeException");
jobject obj = env->NewObject(clz, env->GetMethodID(clz, "<init>", "(Lcom/samsung/lwe/escargot/JavaScriptValue;)V"), exception);
env->Throw(static_cast<jthrowable>(obj));
}
return false;
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptErrorObject_create(JNIEnv* env, jclass clazz,
jobject context, jobject kind,
jstring message)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(kind, "ErrorKind");
THROW_NPE_RETURN_NULL(message, "String");
auto nameMethod = env->GetMethodID(env->GetObjectClass(kind), "name", "()Ljava/lang/String;");
auto kindName = (jstring)env->CallObjectMethod(kind, nameMethod);
auto string = createStringFromJava(env, kindName);
ErrorObjectRef::Code code = Escargot::ErrorObjectRef::None;
if (string == "ReferenceError") {
code = Escargot::ErrorObjectRef::ReferenceError;
} else if (string == "TypeError") {
code = Escargot::ErrorObjectRef::TypeError;
} else if (string == "SyntaxError") {
code = Escargot::ErrorObjectRef::SyntaxError;
} else if (string == "RangeError") {
code = Escargot::ErrorObjectRef::RangeError;
} else if (string == "URIError") {
code = Escargot::ErrorObjectRef::URIError;
} else if (string == "EvalError") {
code = Escargot::ErrorObjectRef::EvalError;
} else if (string == "AggregateError") {
code = Escargot::ErrorObjectRef::AggregateError;
}
StringRef* jsMessage = createJSStringFromJava(env, message);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state,
ErrorObjectRef::Code code, StringRef* jsMessage) -> ValueRef* {
return ErrorObjectRef::create(state, code, jsMessage);
}, code, jsMessage);
assert(evaluatorResult.isSuccessful());
return createJavaObjectFromValue(env, evaluatorResult.result->asErrorObject());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptErrorObject_stack(JNIEnv* env, jobject thiz,
jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ErrorObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asErrorObject();
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ErrorObjectRef* thisValueRef) -> ValueRef* {
return thisValueRef->getOwnProperty(state, StringRef::createFromASCII("stack"))->toString(state);
}, thisValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(), evaluatorResult);
}

View file

@ -1,118 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
static bool stringEndsWith(const std::string& str, const std::string& suffix)
{
return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
}
static Evaluator::EvaluatorResult evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool shouldExecutePendingJobsAtEnd, bool isModule)
{
if (stringEndsWith(srcName->toStdUTF8String(), "mjs")) {
isModule = isModule || true;
}
auto scriptInitializeResult = context->scriptParser()->initializeScript(source, srcName, isModule);
if (!scriptInitializeResult.script) {
LOGD("Script parsing error: ");
switch (scriptInitializeResult.parseErrorCode) {
case Escargot::ErrorObjectRef::Code::SyntaxError:
LOGD("SyntaxError");
break;
case Escargot::ErrorObjectRef::Code::EvalError:
LOGD("EvalError");
break;
case Escargot::ErrorObjectRef::Code::RangeError:
LOGD("RangeError");
break;
case Escargot::ErrorObjectRef::Code::ReferenceError:
LOGD("ReferenceError");
break;
case Escargot::ErrorObjectRef::Code::TypeError:
LOGD("TypeError");
break;
case Escargot::ErrorObjectRef::Code::URIError:
LOGD("URIError");
break;
default:
break;
}
LOGD(": %s\n", scriptInitializeResult.parseErrorMessage->toStdUTF8String().data());
Evaluator::EvaluatorResult evalResult;
evalResult.error = StringRef::createFromASCII("script parsing error");
return evalResult;
}
auto evalResult = ScriptEvaluator::execute(context, [](ExecutionStateRef* state, ScriptRef* script) -> ValueRef* {
return script->execute(state);
},
scriptInitializeResult.script.get());
if (!evalResult.isSuccessful()) {
if (shouldPrintScriptResult) {
LOGD("Uncaught %s:\n", evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
for (size_t i = 0; i < evalResult.stackTrace.size(); i++) {
LOGD("%s (%d:%d)\n", evalResult.stackTrace[i].srcName->toStdUTF8String().data(), (int)evalResult.stackTrace[i].loc.line, (int)evalResult.stackTrace[i].loc.column);
}
}
} else {
if (shouldPrintScriptResult) {
LOGD("%s", evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
}
}
if (shouldExecutePendingJobsAtEnd) {
while (context->vmInstance()->hasPendingJob() || context->vmInstance()->hasPendingJobFromAnotherThread()) {
if (context->vmInstance()->waitEventFromAnotherThread(10)) {
context->vmInstance()->executePendingJobFromAnotherThread();
}
if (context->vmInstance()->hasPendingJob()) {
auto jobResult = context->vmInstance()->executePendingJob();
if (shouldPrintScriptResult) {
if (jobResult.error) {
LOGD("Uncaught %s:(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data());
} else {
LOGD("%s(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data());
}
}
}
}
}
return evalResult;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_Evaluator_evalScript(JNIEnv* env, jclass clazz, jobject context,
jstring source, jstring sourceFileName,
jboolean shouldPrintScriptResult,
jboolean shouldExecutePendingJobsAtEnd)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto ptr = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
Evaluator::EvaluatorResult result = evalScript(ptr->get(), createJSStringFromJava(env, source),
createJSStringFromJava(env, sourceFileName), shouldPrintScriptResult,
shouldExecutePendingJobsAtEnd, false);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, ptr->get(), result);
}

View file

@ -1,113 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptFunctionObject_context(JNIEnv* env, jobject thiz)
{
FunctionObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asFunctionObject();
return createJavaObject(env, thisValueRef->context());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptJavaCallbackFunctionObject_create(JNIEnv* env, jclass clazz,
jobject context,
jstring functionName,
jint argumentCount,
jboolean isConstructor,
jobject callback)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(callback, "Callback");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context),
context);
FunctionObjectRef::NativeFunctionInfo info(
AtomicStringRef::create(contextRef->get(), createJSStringFromJava(env, functionName)),
[](ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructorCall) -> ValueRef* {
auto env = fetchJNIEnvFromCallback();
if (!env) {
LOGE("failed to fetch env from function callback");
return ValueRef::createUndefined();
}
if (env->ExceptionCheck()) {
throwJavaRuntimeException(state);
return ValueRef::createUndefined();
}
ExecutionStateRefTracker tracker(state);
env->PushLocalFrame(32);
jobject callback = ensureScriptObjectExtraData(state->resolveCallee().get())->implementSideData;
auto callbackMethodId = env->GetMethodID(env->GetObjectClass(callback), "callback",
"(Lcom/samsung/lwe/escargot/Context;Lcom/samsung/lwe/escargot/JavaScriptValue;[Lcom/samsung/lwe/escargot/JavaScriptValue;)Ljava/util/Optional;");
jobjectArray javaArgv = env->NewObjectArray(argc, env->FindClass("com/samsung/lwe/escargot/JavaScriptValue"), nullptr);
for (size_t i = 0; i < argc; i ++) {
auto ref = createJavaObjectFromValue(env.get(), argv[i]);
env->SetObjectArrayElement(javaArgv, i, ref);
env->DeleteLocalRef(ref);
}
jobject returnValue = env->CallObjectMethod(
callback,
callbackMethodId,
createJavaObject(env.get(), state->resolveCallee()->context()),
createJavaObjectFromValue(env.get(), thisValue),
javaArgv
);
if (env->ExceptionCheck()) {
env->PopLocalFrame(NULL);
throwJavaRuntimeException(state);
return ValueRef::createUndefined();
}
ValueRef* nativeReturnValue = ValueRef::createUndefined();
if (returnValue) {
auto classOptional = env->GetObjectClass(returnValue);
auto methodIsPresent = env->GetMethodID(classOptional, "isPresent", "()Z");
if (env->CallBooleanMethod(returnValue, methodIsPresent)) {
auto methodGet = env->GetMethodID(classOptional, "get", "()Ljava/lang/Object;");
jobject callbackReturnValue = env->CallObjectMethod(returnValue, methodGet);
nativeReturnValue = unwrapValueRefFromValue(env.get(), env->GetObjectClass(callbackReturnValue), callbackReturnValue);
}
}
env->PopLocalFrame(NULL);
return nativeReturnValue;
},
argumentCount,
isConstructor);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(),
[](ExecutionStateRef* state, FunctionObjectRef::NativeFunctionInfo info) -> ValueRef* {
return FunctionObjectRef::create(state, info);
}, info);
assert(evaluatorResult.isSuccessful());
callback = env->NewGlobalRef(callback);
FunctionObjectRef* fn = evaluatorResult.result->asFunctionObject();
ensureScriptObjectExtraData(fn)->implementSideData = callback;
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject", fn);
}

View file

@ -1,137 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_jsonStringify(JNIEnv* env, jobject thiz,
jobject context, jobject input)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(input, "JavaScriptValue");
auto globalObjectRef = getPersistentPointerFromJava<GlobalObjectRef>(env, env->GetObjectClass(context), thiz);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* inputValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(input), input);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* inputValueRef) -> ValueRef* {
return globalObject->jsonStringify()->call(state, globalObject->json(), 1, &inputValueRef);
}, globalObjectRef->get(), inputValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_jsonParse(JNIEnv* env, jobject thiz,
jobject context, jobject input)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(input, "JavaScriptValue");
auto globalObjectRef = getPersistentPointerFromJava<GlobalObjectRef>(env, env->GetObjectClass(context), thiz);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* inputValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(input), input);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* inputValueRef) -> ValueRef* {
return globalObject->jsonParse()->call(state, globalObject->json(), 1, &inputValueRef);
}, globalObjectRef->get(), inputValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
static jobject callPromiseBuiltinFunction(JNIEnv* env, jobject thiz, jobject context, jobject iterable,
ValueRef* (*closure)(ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef))
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(iterable, "JavaScriptValue");
auto globalObjectRef = getPersistentPointerFromJava<GlobalObjectRef>(env, env->GetObjectClass(context), thiz);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* iterableValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(iterable), iterable);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), closure, globalObjectRef->get(), iterableValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseAll(JNIEnv* env, jobject thiz,
jobject context, jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseAll()->call(state, globalObject->promise(), 1, &iterableValueRef);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseAllSettled(JNIEnv* env, jobject thiz,
jobject context,
jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseAllSettled()->call(state, globalObject->promise(), 1, &iterableValueRef);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseAny(JNIEnv* env, jobject thiz,
jobject context, jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseAny()->call(state, globalObject->promise(), 1, &iterableValueRef);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseRace(JNIEnv* env, jobject thiz,
jobject context, jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseRace()->call(state, globalObject->promise(), 1, &iterableValueRef);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseReject(JNIEnv* env, jobject thiz,
jobject context,
jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseReject()->call(state, globalObject->promise(), 1, &iterableValueRef);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptGlobalObject_promiseResolve(JNIEnv* env, jobject thiz,
jobject context,
jobject iterable)
{
return callPromiseBuiltinFunction(env, thiz, context, iterable, [](ExecutionStateRef* state, GlobalObjectRef* globalObject, ValueRef* iterableValueRef) -> ValueRef* {
return globalObject->promiseResolve()->call(state, globalObject->promise(), 1,
&iterableValueRef);
});
}

View file

@ -1,319 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
static void gcCallback(void* data)
{
auto env = fetchJNIEnvFromCallback();
if (!env) {
LOGE("failed to fetch env from gc event callback");
return;
}
if (!env->ExceptionCheck()) {
env->PushLocalFrame(32);
jclass clazz = env->FindClass("com/samsung/lwe/escargot/NativePointerHolder");
jmethodID mId = env->GetStaticMethodID(clazz, "cleanUp", "()V");
env->CallStaticVoidMethod(clazz, mId);
env->PopLocalFrame(NULL);
}
}
static OptionalRef<StringRef> builtinHelperFileRead(OptionalRef<ExecutionStateRef> state, const char* fileName, const char* builtinName)
{
FILE* fp = fopen(fileName, "r");
if (fp) {
StringRef* src = StringRef::emptyString();
std::string utf8Str;
std::basic_string<unsigned char, std::char_traits<unsigned char>> str;
char buf[512];
bool hasNonLatin1Content = false;
size_t readLen;
while ((readLen = fread(buf, 1, sizeof buf, fp))) {
if (!hasNonLatin1Content) {
for (size_t i = 0; i < readLen; i++) {
unsigned char ch = buf[i];
if (ch & 0x80) {
// check non-latin1 character
hasNonLatin1Content = true;
fseek(fp, 0, SEEK_SET);
break;
}
str += ch;
}
} else {
utf8Str.append(buf, readLen);
}
}
fclose(fp);
if (StringRef::isCompressibleStringEnabled()) {
if (state) {
if (hasNonLatin1Content) {
src = StringRef::createFromUTF8ToCompressibleString(state->context()->vmInstance(), utf8Str.data(), utf8Str.length(), false);
} else {
src = StringRef::createFromLatin1ToCompressibleString(state->context()->vmInstance(), str.data(), str.length());
}
} else {
if (hasNonLatin1Content) {
src = StringRef::createFromUTF8(utf8Str.data(), utf8Str.length(), false);
} else {
src = StringRef::createFromLatin1(str.data(), str.length());
}
}
} else {
if (hasNonLatin1Content) {
src = StringRef::createFromUTF8(utf8Str.data(), utf8Str.length(), false);
} else {
src = StringRef::createFromLatin1(str.data(), str.length());
}
}
return src;
} else {
if (state) {
const size_t maxNameLength = 980;
if ((strnlen(builtinName, maxNameLength) + strnlen(fileName, maxNameLength)) < maxNameLength) {
char msg[1024];
snprintf(msg, sizeof(msg), "GlobalObject.%s: cannot open file %s", builtinName, fileName);
state->throwException(URIErrorObjectRef::create(state.get(), StringRef::createFromUTF8(msg, strnlen(msg, sizeof msg))));
} else {
state->throwException(URIErrorObjectRef::create(state.get(), StringRef::createFromASCII("invalid file name")));
}
} else {
LOGE("%s", fileName);
}
return nullptr;
}
}
class ShellPlatform : public PlatformRef {
public:
bool m_canBlock;
ShellPlatform()
: m_canBlock(true)
{
}
void setCanBlock(bool b)
{
m_canBlock = b;
}
virtual void markJSJobEnqueued(ContextRef* relatedContext) override
{
// ignore. we always check pending job after eval script
}
virtual void markJSJobFromAnotherThreadExists(ContextRef* relatedContext) override
{
// ignore. we always check pending job after eval script
}
virtual LoadModuleResult onLoadModule(ContextRef* relatedContext, ScriptRef* whereRequestFrom, StringRef* moduleSrc, ModuleType type) override
{
std::string referrerPath = whereRequestFrom->src()->toStdUTF8String();
auto& loadedModules = *reinterpret_cast<std::vector<std::tuple<std::string, ContextRef*, PersistentRefHolder<ScriptRef>>>*>(threadLocalCustomData());
for (size_t i = 0; i < loadedModules.size(); i++) {
if (std::get<2>(loadedModules[i]) == whereRequestFrom) {
referrerPath = std::get<0>(loadedModules[i]);
break;
}
}
std::string absPath = absolutePath(referrerPath, moduleSrc->toStdUTF8String());
if (absPath.length() == 0) {
std::string s = "Error reading : " + moduleSrc->toStdUTF8String();
return LoadModuleResult(ErrorObjectRef::Code::None, StringRef::createFromUTF8(s.data(), s.length()));
}
for (size_t i = 0; i < loadedModules.size(); i++) {
if (std::get<0>(loadedModules[i]) == absPath && std::get<1>(loadedModules[i]) == relatedContext) {
return LoadModuleResult(std::get<2>(loadedModules[i]));
}
}
OptionalRef<StringRef> source = builtinHelperFileRead(nullptr, absPath.data(), "");
if (!source) {
std::string s = "Error reading : " + absPath;
return LoadModuleResult(ErrorObjectRef::Code::None, StringRef::createFromUTF8(s.data(), s.length()));
}
ScriptParserRef::InitializeScriptResult parseResult;
StringRef* srcName = StringRef::createFromUTF8(absPath.data(), absPath.size());
if (type == ModuleJSON) {
parseResult = relatedContext->scriptParser()->initializeJSONModule(source.value(), srcName);
} else {
parseResult = relatedContext->scriptParser()->initializeScript(source.value(), srcName, true);
}
if (!parseResult.isSuccessful()) {
return LoadModuleResult(parseResult.parseErrorCode, parseResult.parseErrorMessage);
}
return LoadModuleResult(parseResult.script.get());
}
virtual void didLoadModule(ContextRef* relatedContext, OptionalRef<ScriptRef> referrer, ScriptRef* loadedModule) override
{
std::string path;
if (referrer && loadedModule->src()->length() && loadedModule->src()->charAt(0) != '/') {
path = absolutePath(referrer->src()->toStdUTF8String(), loadedModule->src()->toStdUTF8String());
} else {
path = absolutePath(loadedModule->src()->toStdUTF8String());
}
auto& loadedModules = *reinterpret_cast<std::vector<std::tuple<std::string, ContextRef*, PersistentRefHolder<ScriptRef>>>*>(threadLocalCustomData());
loadedModules.push_back(std::make_tuple(path, relatedContext, PersistentRefHolder<ScriptRef>(loadedModule)));
}
virtual void hostImportModuleDynamically(ContextRef* relatedContext, ScriptRef* referrer, StringRef* src, ModuleType type, PromiseObjectRef* promise) override
{
LoadModuleResult loadedModuleResult = onLoadModule(relatedContext, referrer, src, type);
notifyHostImportModuleDynamicallyResult(relatedContext, referrer, src, promise, loadedModuleResult);
}
virtual bool canBlockExecution(ContextRef* relatedContext) override
{
return m_canBlock;
}
virtual void* allocateThreadLocalCustomData() override
{
return new std::vector<std::tuple<std::string /* abs path */, ContextRef*, PersistentRefHolder<ScriptRef>>>();
}
virtual void deallocateThreadLocalCustomData() override
{
delete reinterpret_cast<std::vector<std::tuple<std::string, ContextRef*, PersistentRefHolder<ScriptRef>>>*>(threadLocalCustomData());
}
private:
std::string dirnameOf(const std::string& fname)
{
size_t pos = fname.find_last_of("/");
if (std::string::npos == pos) {
pos = fname.find_last_of("\\/");
}
return (std::string::npos == pos)
? ""
: fname.substr(0, pos);
}
std::string absolutePath(const std::string& referrerPath, const std::string& src)
{
std::string utf8MayRelativePath = dirnameOf(referrerPath) + "/" + src;
auto absPath = realpath(utf8MayRelativePath.data(), nullptr);
if (!absPath) {
return std::string();
}
std::string utf8AbsolutePath = absPath;
free(absPath);
return utf8AbsolutePath;
}
std::string absolutePath(const std::string& src)
{
auto absPath = realpath(src.data(), nullptr);
if (!absPath) {
return std::string();
}
std::string utf8AbsolutePath = absPath;
free(absPath);
return utf8AbsolutePath;
}
};
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Globals_initializeGlobals(JNIEnv* env, jclass clazz)
{
if (!Globals::isInitialized()) {
Globals::initialize(new ShellPlatform());
Memory::addGCEventListener(Memory::MARK_START, gcCallback, nullptr);
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Globals_finalizeGlobals(JNIEnv* env, jclass clazz)
{
if (Globals::isInitialized()) {
// java object cleanup
gcCallback(nullptr);
Memory::removeGCEventListener(Memory::MARK_START, gcCallback, nullptr);
Globals::finalize();
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Globals_initializeThread(JNIEnv* env, jclass clazz)
{
if (!Globals::isInitialized()) {
Globals::initializeThread();
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Globals_finalizeThread(JNIEnv* env, jclass clazz)
{
if (Globals::isInitialized()) {
Globals::finalizeThread();
}
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_Globals_isInitialized(JNIEnv* env, jclass clazz)
{
return Globals::isInitialized();
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_samsung_lwe_escargot_Globals_version(JNIEnv* env, jclass clazz)
{
std::string version = Globals::version();
std::basic_string<uint16_t> u16Version;
for (auto c: version) {
u16Version.push_back(c);
}
return env->NewString(u16Version.data(), u16Version.length());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_samsung_lwe_escargot_Globals_buildDate(JNIEnv* env, jclass clazz)
{
std::string version = Globals::buildDate();
std::basic_string<uint16_t> u16Version;
for (auto c: version) {
u16Version.push_back(c);
}
return env->NewString(u16Version.data(), u16Version.length());
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Memory_gc(JNIEnv* env, jclass clazz)
{
Memory::gc();
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_samsung_lwe_escargot_Memory_heapSize(JNIEnv* env, jclass clazz)
{
return Memory::heapSize();
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_samsung_lwe_escargot_Memory_totalSize(JNIEnv* env, jclass clazz)
{
return Memory::totalSize();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_Memory_setGCFrequency(JNIEnv* env, jclass clazz, jint value)
{
Memory::setGCFrequency(value);
}

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_NativePointerHolder_releaseNativePointerMemory(JNIEnv* env,
jclass clazz, jlong pointer)
{
uint64_t ptrInNumber = (uint64_t)(pointer);
if (ptrInNumber > g_nonPointerValueLast && !(pointer & 1)) {
PersistentRefHolder<void>* pRef = reinterpret_cast<PersistentRefHolder<void>*>(pointer);
delete pRef;
}
}

View file

@ -1,173 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_create(JNIEnv* env, jclass clazz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state) -> ValueRef* {
return ObjectRef::create(state);
});
assert(evaluatorResult.isSuccessful());
return createJavaObjectFromValue(env, evaluatorResult.result->asObject());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_get(JNIEnv* env, jobject thiz, jobject context,
jobject propertyName)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(propertyName, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
ValueRef* propertyNameValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(propertyName), propertyName);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ObjectRef* thisValueRef, ValueRef* propertyNameValueRef) -> ValueRef* {
return thisValueRef->get(state, propertyNameValueRef);
}, thisValueRef, propertyNameValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_set(JNIEnv* env, jobject thiz, jobject context,
jobject propertyName, jobject value)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(propertyName, "JavaScriptValue");
THROW_NPE_RETURN_NULL(value, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
ValueRef* propertyNameValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(propertyName), propertyName);
ValueRef* valueRef = unwrapValueRefFromValue(env, env->GetObjectClass(value), value);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ObjectRef* thisValueRef, ValueRef* propertyNameValueRef, ValueRef* valueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->set(state, propertyNameValueRef, valueRef));
}, thisValueRef, propertyNameValueRef, valueRef);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_defineDataProperty(JNIEnv* env, jobject thiz,
jobject context,
jobject propertyName,
jobject value,
jboolean isWritable,
jboolean isEnumerable,
jboolean isConfigurable)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(propertyName, "JavaScriptValue");
THROW_NPE_RETURN_NULL(value, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
ValueRef* propertyNameValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(propertyName), propertyName);
ValueRef* valueRef = unwrapValueRefFromValue(env, env->GetObjectClass(value), value);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ObjectRef* thisValueRef, ValueRef* propertyNameValueRef, ValueRef* valueRef,
jboolean isWritable,
jboolean isEnumerable,
jboolean isConfigurable) -> ValueRef* {
return ValueRef::create(thisValueRef->defineDataProperty(state, propertyNameValueRef, valueRef, isWritable, isEnumerable, isConfigurable));
}, thisValueRef, propertyNameValueRef, valueRef, isWritable, isEnumerable, isConfigurable);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_getOwnProperty(JNIEnv* env, jobject thiz,
jobject context,
jobject propertyName)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(propertyName, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
ValueRef* propertyNameValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(propertyName), propertyName);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ObjectRef* thisValueRef, ValueRef* propertyNameValueRef) -> ValueRef* {
return thisValueRef->getOwnProperty(state, propertyNameValueRef);
}, thisValueRef, propertyNameValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_setExtraData(JNIEnv* env, jobject thiz,
jobject object)
{
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
jobject extraData = nullptr;
if (object) {
auto classOptional = env->GetObjectClass(object);
auto methodIsPresent = env->GetMethodID(classOptional, "isPresent", "()Z");
if (env->CallBooleanMethod(object, methodIsPresent)) {
auto methodGet = env->GetMethodID(classOptional, "get", "()Ljava/lang/Object;");
jboolean isSucceed;
extraData = env->CallObjectMethod(object, methodGet);
extraData = env->NewGlobalRef(extraData);
}
}
ensureScriptObjectExtraData(thisValueRef)->userData = extraData;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptObject_extraData(JNIEnv* env, jobject thiz)
{
ObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asObject();
jobject extraData = nullptr;
if (thisValueRef->extraData()) {
extraData = ensureScriptObjectExtraData(thisValueRef)->userData;
}
jclass optionalClazz = env->FindClass("java/util/Optional");
if (extraData) {
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "of",
"(Ljava/lang/Object;)Ljava/util/Optional;"),
extraData);
} else {
return env->CallStaticObjectMethod(optionalClazz,
env->GetStaticMethodID(optionalClazz, "empty",
"()Ljava/util/Optional;"));
}
}

View file

@ -1,172 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_create(JNIEnv* env, jclass clazz,
jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state) -> ValueRef* {
return PromiseObjectRef::create(state);
});
assert(evaluatorResult.isSuccessful());
return createJavaObjectFromValue(env, evaluatorResult.result->asPromiseObject());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_state(JNIEnv* env, jobject thiz)
{
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
jclass enumClass = env->FindClass(
"com/samsung/lwe/escargot/JavaScriptPromiseObject$PromiseState");
jfieldID enumFieldID;
PromiseObjectRef::PromiseState state = thisValueRef->state();
if (state == PromiseObjectRef::Pending) {
enumFieldID = env->GetStaticFieldID(enumClass, "Pending",
"Lcom/samsung/lwe/escargot/JavaScriptPromiseObject$PromiseState;");
} else if (state == PromiseObjectRef::FulFilled) {
enumFieldID = env->GetStaticFieldID(enumClass, "FulFilled",
"Lcom/samsung/lwe/escargot/JavaScriptPromiseObject$PromiseState;");
} else {
enumFieldID = env->GetStaticFieldID(enumClass, "Rejected",
"Lcom/samsung/lwe/escargot/JavaScriptPromiseObject$PromiseState;");
}
return env->GetStaticObjectField(enumClass, enumFieldID);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_promiseResult(JNIEnv* env, jobject thiz)
{
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
return createJavaObjectFromValue(env, thisValueRef->promiseResult());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_then__Lcom_samsung_lwe_escargot_Context_2Lcom_samsung_lwe_escargot_JavaScriptValue_2(
JNIEnv* env, jobject thiz, jobject context, jobject handler)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(handler, "JavaScriptValue");
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
ValueRef* handlerRef = unwrapValueRefFromValue(env, env->GetObjectClass(handler), handler);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, PromiseObjectRef* promiseObject, ValueRef* handlerRef) -> ValueRef* {
return promiseObject->then(state, handlerRef);
}, thisValueRef, handlerRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_then__Lcom_samsung_lwe_escargot_Context_2Lcom_samsung_lwe_escargot_JavaScriptValue_2Lcom_samsung_lwe_escargot_JavaScriptValue_2(
JNIEnv* env, jobject thiz, jobject context, jobject onFulfilled, jobject onRejected)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(onFulfilled, "JavaScriptValue");
THROW_NPE_RETURN_NULL(onRejected, "JavaScriptValue");
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
ValueRef* onFulfilledRef = unwrapValueRefFromValue(env, env->GetObjectClass(onFulfilled), onFulfilled);
ValueRef* onRejectedRef = unwrapValueRefFromValue(env, env->GetObjectClass(onRejected), onRejected);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, PromiseObjectRef* promiseObject, ValueRef* onFulfilledRef, ValueRef* onRejectedRef) -> ValueRef* {
return promiseObject->then(state, onFulfilledRef, onRejectedRef);
}, thisValueRef, onFulfilledRef, onRejectedRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_catchOperation(JNIEnv* env, jobject thiz,
jobject context,
jobject handler)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(handler, "JavaScriptValue");
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
ValueRef* handlerRef = unwrapValueRefFromValue(env, env->GetObjectClass(handler), handler);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, PromiseObjectRef* promiseObject, ValueRef* handlerRef) -> ValueRef* {
return promiseObject->catchOperation(state, handlerRef);
}, thisValueRef, handlerRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_fulfill(JNIEnv* env, jobject thiz,
jobject context, jobject value)
{
THROW_NPE_RETURN_VOID(context, "Context");
THROW_NPE_RETURN_VOID(value, "JavaScriptValue");
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
ValueRef* valueRef = unwrapValueRefFromValue(env, env->GetObjectClass(value), value);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, PromiseObjectRef* promiseObject, ValueRef* valueRef) -> ValueRef* {
promiseObject->fulfill(state, valueRef);
return ValueRef::createUndefined();
}, thisValueRef, valueRef);
assert(evaluatorResult.isSuccessful());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_reject(JNIEnv* env, jobject thiz,
jobject context, jobject reason)
{
THROW_NPE_RETURN_VOID(context, "Context");
THROW_NPE_RETURN_VOID(reason, "JavaScriptValue");
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
ValueRef* reasonRef = unwrapValueRefFromValue(env, env->GetObjectClass(reason), reason);
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, PromiseObjectRef* promiseObject, ValueRef* reasonRef) -> ValueRef* {
promiseObject->reject(state, reasonRef);
return ValueRef::createUndefined();
}, thisValueRef, reasonRef);
assert(evaluatorResult.isSuccessful());
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_hasHandler(JNIEnv* env, jobject thiz)
{
PromiseObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asPromiseObject();
return thisValueRef->hasResolveHandlers() || thisValueRef->hasRejectHandlers();
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptString_create(JNIEnv* env, jclass clazz, jstring value)
{
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptString", createJSStringFromJava(env, value));
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_samsung_lwe_escargot_JavaScriptString_toJavaString(JNIEnv* env, jobject thiz)
{
StringRef* string = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asString();
return createJavaStringFromJS(env, string);
}

View file

@ -1,79 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptSymbol_create(JNIEnv* env, jclass clazz, jobject value)
{
OptionalRef<StringRef> descString;
if (value) {
auto classOptionalJavaScriptString = env->GetObjectClass(value);
auto methodIsPresent = env->GetMethodID(classOptionalJavaScriptString, "isPresent", "()Z");
if (env->CallBooleanMethod(value, methodIsPresent)) {
auto methodGet = env->GetMethodID(classOptionalJavaScriptString, "get", "()Ljava/lang/Object;");
jboolean isSucceed;
jobject javaObjectValue = env->CallObjectMethod(value, methodGet);
descString = unwrapValueRefFromValue(env, env->GetObjectClass(javaObjectValue), javaObjectValue)->asString();
}
}
return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptSymbol", SymbolRef::create(descString));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptSymbol_fromGlobalSymbolRegistry(JNIEnv* env, jclass clazz,
jobject vm,
jobject stringKey)
{
THROW_NPE_RETURN_NULL(vm, "VMInstance");
THROW_NPE_RETURN_NULL(stringKey, "JavaScriptString");
auto ptr = getPersistentPointerFromJava<VMInstanceRef>(env, env->GetObjectClass(vm), vm);
auto key = unwrapValueRefFromValue(env, env->GetObjectClass(stringKey), stringKey);
auto symbol = SymbolRef::fromGlobalSymbolRegistry(ptr->get(), key->asString());
return createJavaObjectFromValue(env, symbol);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptSymbol_descriptionString(JNIEnv* env, jobject thiz)
{
auto desc = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asSymbol()->descriptionString();
return createJavaObjectFromValue(env, desc);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptSymbol_descriptionValue(JNIEnv* env, jobject thiz)
{
auto desc = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asSymbol()->descriptionValue();
return createJavaObjectFromValue(env, desc);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptSymbol_symbolDescriptiveString(JNIEnv* env, jobject thiz)
{
auto desc = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asSymbol()->symbolDescriptiveString();
return createJavaObjectFromValue(env, desc);
}

View file

@ -1,56 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_VMInstance_create(JNIEnv *env, jclass clazz, jobject locale,
jobject timezone)
{
THROW_NPE_RETURN_NULL(locale, "Optional<String>");
THROW_NPE_RETURN_NULL(timezone, "Optional<String>");
std::string localeString = fetchStringFromJavaOptionalString(env, locale);
std::string timezoneString = fetchStringFromJavaOptionalString(env, timezone);
auto vmRef = VMInstanceRef::create(localeString.length() ? localeString.data() : nullptr,
timezoneString.length() ? timezoneString.data() : nullptr);
return createJavaObject(env, vmRef.get());
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_VMInstance_hasPendingJob(JNIEnv* env, jobject thiz)
{
auto vmPtr = getPersistentPointerFromJava<VMInstanceRef>(env, env->GetObjectClass(thiz),
thiz);
return vmPtr->get()->hasPendingJob();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_samsung_lwe_escargot_VMInstance_executePendingJob(JNIEnv* env, jobject thiz)
{
auto vmPtr = getPersistentPointerFromJava<VMInstanceRef>(env, env->GetObjectClass(thiz),
thiz);
if (vmPtr->get()->hasPendingJob()) {
vmPtr->get()->executePendingJob();
}
}

View file

@ -1,500 +0,0 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "EscargotJNI.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_createUndefined(JNIEnv* env, jclass clazz)
{
return createJavaValueObject(env, clazz, ValueRef::createUndefined());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_createNull(JNIEnv* env, jclass clazz)
{
return createJavaValueObject(env, clazz, ValueRef::createNull());
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_create__I(JNIEnv* env, jclass clazz, jint value)
{
return createJavaValueObject(env, clazz, ValueRef::create(value));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_create__D(JNIEnv* env, jclass clazz, jdouble value)
{
return createJavaValueObject(env, clazz, ValueRef::create(value));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_create__Z(JNIEnv* env, jclass clazz, jboolean value)
{
return createJavaValueObject(env, clazz, ValueRef::create(static_cast<bool>(value)));
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isUndefined(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isUndefined();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isNull(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isNull();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isUndefinedOrNull(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isUndefinedOrNull();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isNumber(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isNumber();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isInt32(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isInt32();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isBoolean(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isBoolean();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isTrue(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isTrue();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isFalse(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isFalse();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isString(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isString();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isSymbol(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isSymbol();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isBigInt(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isBigInt();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isCallable(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isCallable();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isObject(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isObject();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isArrayObject(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isArrayObject();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isFunctionObject(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isFunctionObject();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isPromiseObject(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isPromiseObject();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_isErrorObject(JNIEnv* env, jobject thiz)
{
return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->isErrorObject();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asBoolean(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Boolean);
return ref->asBoolean();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asInt32(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Int32);
return ref->asInt32();
}
extern "C"
JNIEXPORT jdouble JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asNumber(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Number);
return ref->asNumber();
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptString(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, String);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptSymbol(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Symbol);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptBigInt(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, BigInt);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptObject(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Object);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptArrayObject(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, ArrayObject);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptFunctionObject(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, FunctionObject);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptPromiseObject(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, PromiseObject);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptErrorObject(JNIEnv* env, jobject thiz)
{
ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, ErrorObject);
return thiz;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toString(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return thisValueRef->toString(state);
}, thisValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toNumber(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->toNumber(state));
}, thisValueRef);
return createOptionalValueFromEvaluatorDoubleResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toInteger(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->toInteger(state));
}, thisValueRef);
return createOptionalValueFromEvaluatorDoubleResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toInt32(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->toInt32(state));
}, thisValueRef);
return createOptionalValueFromEvaluatorIntegerResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toBoolean(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->toBoolean(state));
}, thisValueRef);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_toObject(JNIEnv* env, jobject thiz, jobject context)
{
THROW_NPE_RETURN_NULL(context, "Context");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef) -> ValueRef* {
return thisValueRef->toObject(state);
}, thisValueRef);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_abstractEqualsTo(JNIEnv* env, jobject thiz,
jobject context, jobject other)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(other, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
ValueRef* otherValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(other), other);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef, ValueRef* otherValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->abstractEqualsTo(state, otherValueRef));
}, thisValueRef, otherValueRef);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_equalsTo(JNIEnv* env, jobject thiz, jobject context,
jobject other)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(other, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
ValueRef* otherValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(other), other);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef, ValueRef* otherValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->equalsTo(state, otherValueRef));
}, thisValueRef, otherValueRef);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_instanceOf(JNIEnv* env, jobject thiz, jobject context,
jobject other)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(other, "JavaScriptValue");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
ValueRef* otherValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(other), other);
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(), [](ExecutionStateRef* state, ValueRef* thisValueRef, ValueRef* otherValueRef) -> ValueRef* {
return ValueRef::create(thisValueRef->instanceOf(state, otherValueRef));
}, thisValueRef, otherValueRef);
return createOptionalValueFromEvaluatorBooleanResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_call(JNIEnv* env, jobject thiz, jobject context,
jobject receiver, jobjectArray argv)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(receiver, "JavaScriptValue");
THROW_NPE_RETURN_NULL(argv, "JavaScriptValue[]");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
ValueRef* receiverValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(receiver), receiver);
auto argvLength = env->GetArrayLength(argv);
ValueRef** argVector = reinterpret_cast<ValueRef**>(Memory::gcMalloc(argvLength * sizeof(ValueRef*)));
for (jsize i = 0; i < argvLength; i++) {
jobject e = env->GetObjectArrayElement(argv, i);
argVector[i] = unwrapValueRefFromValue(env, env->GetObjectClass(e), e);
env->DeleteLocalRef(e);
}
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(),
[](ExecutionStateRef* state, ValueRef* thisValueRef, ValueRef* receiverValueRef, ValueRef** argVector, int argvLength) -> ValueRef* {
return thisValueRef->call(state, receiverValueRef, argvLength, argVector);
}, thisValueRef, receiverValueRef, argVector, argvLength);
Memory::gcFree(argVector);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_samsung_lwe_escargot_JavaScriptValue_construct(JNIEnv* env, jobject thiz, jobject context,
jobjectArray argv)
{
THROW_NPE_RETURN_NULL(context, "Context");
THROW_NPE_RETURN_NULL(argv, "JavaScriptValue[]");
auto contextRef = getPersistentPointerFromJava<ContextRef>(env, env->GetObjectClass(context), context);
ValueRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz);
auto argvLength = env->GetArrayLength(argv);
ValueRef** argVector = reinterpret_cast<ValueRef**>(Memory::gcMalloc(argvLength * sizeof(ValueRef*)));
for (jsize i = 0; i < argvLength; i++) {
jobject e = env->GetObjectArrayElement(argv, i);
argVector[i] = unwrapValueRefFromValue(env, env->GetObjectClass(e), e);
env->DeleteLocalRef(e);
}
auto evaluatorResult = ScriptEvaluator::execute(contextRef->get(),
[](ExecutionStateRef* state, ValueRef* thisValueRef, ValueRef** argVector, int argvLength) -> ValueRef* {
return thisValueRef->construct(state, argvLength, argVector);
}, thisValueRef, argVector, argvLength);
Memory::gcFree(argVector);
return createOptionalValueFromEvaluatorJavaScriptValueResult(env, context, contextRef->get(),
evaluatorResult);
}

File diff suppressed because it is too large Load diff

View file

@ -9,11 +9,10 @@ final public class Bridge {
public abstract static class Adapter {
/**
* @param context Context from callee
* @param data the data parameter contains value when call this function from JavaScript
* @return if want to return data to JavaScript callback, you can return value from this callback.
*/
public abstract Optional<JavaScriptValue> callback(Context context, Optional<JavaScriptValue> data);
public abstract Optional<JavaScriptValue> callback(Optional<JavaScriptValue> data);
}
/**

View file

@ -19,7 +19,6 @@ public class Context extends NativePointerHolder {
return lastThrownException;
}
public native JavaScriptGlobalObject getGlobalObject();
public native boolean throwException(JavaScriptValue exception);
protected Optional<JavaScriptValue> m_lastThrownException = Optional.empty();
}

View file

@ -7,19 +7,6 @@ final public class Evaluator {
private Evaluator() {
}
/**
*
* @param context
* @param source
* @param sourceFileName
* @return return result if eval was successful
*/
static public Optional<JavaScriptValue> evalScript(Context context, String source, String sourceFileName)
{
return evalScript(context, source, sourceFileName, false);
}
/**
* @param context
* @param source
@ -27,20 +14,5 @@ final public class Evaluator {
* @param shouldPrintScriptResult
* @return return result if eval was successful
*/
static public Optional<JavaScriptValue> evalScript(Context context, String source, String sourceFileName,
boolean shouldPrintScriptResult)
{
return evalScript(context, source, sourceFileName, shouldPrintScriptResult, true);
}
/**
* @param context
* @param source
* @param sourceFileName
* @param shouldPrintScriptResult
* @param shouldExecutePendingJobsAtEnd
* @return return result if eval was successful
*/
static native public Optional<JavaScriptValue> evalScript(Context context, String source, String sourceFileName,
boolean shouldPrintScriptResult, boolean shouldExecutePendingJobsAtEnd);
static native public Optional<JavaScriptValue> evalScript(Context context, String source, String sourceFileName, boolean shouldPrintScriptResult);
}

View file

@ -1,31 +1,10 @@
package com.samsung.lwe.escargot;
import java.util.Optional;
public class JavaScriptArrayObject extends JavaScriptObject {
protected JavaScriptArrayObject(long nativePointer)
{
super(nativePointer);
}
static public native JavaScriptArrayObject create(Context context);
/**
*
* @param context
* @param from
* @return
*/
static public Optional<JavaScriptArrayObject> create(Context context, JavaScriptValue[] from)
{
JavaScriptArrayObject ret = JavaScriptArrayObject.create(context);
ret.setLength(context, from.length);
for (int i = 0; i < from.length; i ++) {
Optional<Boolean> b = ret.set(context, JavaScriptValue.create(i), from[i]);
if (!b.isPresent() || !b.get())
return Optional.empty();
}
return Optional.of(ret);
}
public native long length(Context context);
public native void setLength(Context context, long newLength);
}

View file

@ -1,23 +0,0 @@
package com.samsung.lwe.escargot;
import java.util.Optional;
public class JavaScriptErrorObject extends JavaScriptObject {
protected JavaScriptErrorObject(long nativePointer)
{
super(nativePointer);
}
public enum ErrorKind {
None,
ReferenceError,
TypeError,
SyntaxError,
RangeError,
URIError,
EvalError,
AggregateError
}
static public native JavaScriptErrorObject create(Context context, ErrorKind kind, String message);
public native Optional<JavaScriptString> stack(Context context);
}

View file

@ -5,5 +5,4 @@ public class JavaScriptFunctionObject extends JavaScriptObject {
{
super(nativePointer);
}
public native Context context();
}

View file

@ -22,52 +22,4 @@ public class JavaScriptGlobalObject extends JavaScriptObject {
* @return
*/
public native Optional<JavaScriptValue> jsonParse(Context context, JavaScriptValue input);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseAll(Context context, JavaScriptValue iterable);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseAllSettled(Context context, JavaScriptValue iterable);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseAny(Context context, JavaScriptValue iterable);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseRace(Context context, JavaScriptValue iterable);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseReject(Context context, JavaScriptValue iterable);
/**
*
* @param context
* @param iterable
* @return
*/
public native Optional<JavaScriptValue> promiseResolve(Context context, JavaScriptValue iterable);
}

View file

@ -11,12 +11,11 @@ public class JavaScriptJavaCallbackFunctionObject extends JavaScriptFunctionObje
public abstract static class Callback {
/**
*
* @param context
* @param receiverValue
* @param arguments
* @return
*/
public abstract Optional<JavaScriptValue> callback(Context context, JavaScriptValue receiverValue, JavaScriptValue arguments[]);
public abstract Optional<JavaScriptValue> callback(JavaScriptValue receiverValue, JavaScriptValue arguments[]);
}
/**

View file

@ -54,17 +54,4 @@ public class JavaScriptObject extends JavaScriptValue {
* @return JavaScriptValue or Optional.empty if there was a exception while executing getOwnProperty function
*/
public native Optional<JavaScriptValue> getOwnProperty(Context context, JavaScriptValue propertyName);
/**
* store Java Object in JavaScriptObject
* @param object
*/
public native void setExtraData(Optional<Object> object);
/**
* returns stored Java object in JavaScriptObject
* this function returns `Optional with Object` or `empty Optional`
* @return
*/
public native Optional<Object> extraData();
}

View file

@ -1,60 +0,0 @@
package com.samsung.lwe.escargot;
import java.util.Optional;
public class JavaScriptPromiseObject extends JavaScriptObject {
protected JavaScriptPromiseObject(long nativePointer)
{
super(nativePointer);
}
static public native JavaScriptPromiseObject create(Context context);
enum PromiseState {
Pending,
FulFilled,
Rejected
};
public native PromiseState state();
public native JavaScriptValue promiseResult();
/**
*
* @param context
* @param handler
* @return
*/
public native Optional<JavaScriptObject> then(Context context, JavaScriptValue handler);
/**
*
* @param context
* @param onFulfilled
* @param onRejected
* @return
*/
public native Optional<JavaScriptObject> then(Context context, JavaScriptValue onFulfilled, JavaScriptValue onRejected);
/**
*
* @param context
* @param handler
* @return
*/
public native Optional<JavaScriptObject> catchOperation(Context context, JavaScriptValue handler);
/**
*
* @param context
* @param value
*/
public native void fulfill(Context context, JavaScriptValue value);
/**
*
* @param context
* @param reason
*/
public native void reject(Context context, JavaScriptValue reason);
public native boolean hasHandler();
}

View file

@ -5,6 +5,5 @@ public class JavaScriptString extends JavaScriptValue {
{
super(nativePointer, true);
}
native static public JavaScriptString create(String value);
native public String toJavaString();
}

View file

@ -7,10 +7,7 @@ public class JavaScriptSymbol extends JavaScriptValue {
{
super(nativePointer, true);
}
native static public JavaScriptSymbol create(Optional<JavaScriptString> value);
native public JavaScriptString descriptionString();
native public JavaScriptValue descriptionValue();
native public Optional<JavaScriptString> description();
native public JavaScriptString symbolDescriptiveString();
/**

View file

@ -18,6 +18,8 @@ public class JavaScriptValue extends NativePointerHolder {
native static public JavaScriptValue create(boolean value);
native static public JavaScriptValue create(int value);
native static public JavaScriptValue create(double value);
native static public JavaScriptString create(String value);
native static public JavaScriptSymbol create(Optional<JavaScriptString> value);
native public boolean isUndefined();
native public boolean isNull();
@ -34,9 +36,10 @@ public class JavaScriptValue extends NativePointerHolder {
native public boolean isObject();
native public boolean isArrayObject();
native public boolean isFunctionObject();
native public boolean isPromiseObject();
native public boolean isErrorObject();
// as{ .. } methods don't check type is correct
// if you want to use these as{ .. } methods
// you must check type before use!
native public boolean asBoolean();
native public int asInt32();
native public double asNumber();
@ -46,8 +49,6 @@ public class JavaScriptValue extends NativePointerHolder {
native public JavaScriptObject asScriptObject();
native public JavaScriptArrayObject asScriptArrayObject();
native public JavaScriptFunctionObject asScriptFunctionObject();
native public JavaScriptPromiseObject asScriptPromiseObject();
native public JavaScriptErrorObject asScriptErrorObject();
native public Optional<JavaScriptString> toString(Context context);
native public Optional<Boolean> toBoolean(Context context);

View file

@ -1,16 +0,0 @@
package com.samsung.lwe.escargot.internal;
import com.samsung.lwe.escargot.JavaScriptValue;
public class JavaScriptRuntimeException extends RuntimeException {
public JavaScriptRuntimeException(JavaScriptValue exception)
{
this.m_exception = exception;
}
public JavaScriptValue exception() {
return m_exception;
}
private JavaScriptValue m_exception;
}

View file

@ -1,239 +0,0 @@
package com.samsung.lwe.escargot.util;
import com.samsung.lwe.escargot.Context;
import com.samsung.lwe.escargot.JavaScriptPromiseObject;
import com.samsung.lwe.escargot.JavaScriptValue;
import com.samsung.lwe.escargot.VMInstance;
import java.util.ArrayList;
public class MultiThreadExecutor {
public static interface WorkerThreadEndNotifier {
/**
* called by worker thread before thread exiting
* @param instance
*/
public abstract void notify(MultiThreadExecutor executor, ExecutorInstance instance);
}
VMInstance m_vmInstance;
Thread m_javaScriptThread;
ArrayList<ExecutorInstance> m_activeInstances = new ArrayList<>();
ArrayList<ExecutorInstance> m_endedInstances = new ArrayList<>();
WorkerThreadEndNotifier m_workerThreadEndNotifier;
/**
* init with current thread as JavaScript Thread
* and manual threadEndNotifier
* @param vmInstance
*/
public MultiThreadExecutor(VMInstance vmInstance)
{
this(vmInstance, (executor, instance) -> {
}, Thread.currentThread());
}
/**
* init with manual threadEndNotifier
* @param vmInstance
* @param javaScriptThread
*/
public MultiThreadExecutor(VMInstance vmInstance, Thread javaScriptThread)
{
this(vmInstance, (executor, instance) -> {
}, javaScriptThread);
}
/**
* init with current thread as JavaScript Thread
* and manual threadEndNotifier
* @param vmInstance
* @param threadEndNotifier
*/
public MultiThreadExecutor(VMInstance vmInstance, WorkerThreadEndNotifier threadEndNotifier)
{
this(vmInstance, threadEndNotifier, Thread.currentThread());
}
/**
* @param vmInstance
* @param threadEndNotifier
* @param javaScriptThread
*/
public MultiThreadExecutor(VMInstance vmInstance, WorkerThreadEndNotifier threadEndNotifier, Thread javaScriptThread)
{
if (vmInstance == null || threadEndNotifier == null || javaScriptThread == null) {
throw new NullPointerException();
}
m_javaScriptThread = javaScriptThread;
m_vmInstance = vmInstance;
m_workerThreadEndNotifier = threadEndNotifier;
}
public static abstract class ResultBuilder {
public abstract JavaScriptValue build(Context scriptContext, ResultBuilderContext builderContext);
}
public static class ResultBuilderContext {
private boolean m_wasSuccessful;
private Object m_data;
public ResultBuilderContext(boolean wasSuccessful, Object data) {
m_wasSuccessful = wasSuccessful;
m_data = data;
}
public Object data() {
return m_data;
}
public boolean wasSuccessful() {
return m_wasSuccessful;
}
}
public static abstract class Executor {
public abstract ResultBuilderContext run();
}
public static class ExecutorInstance {
private Context m_context;
private JavaScriptPromiseObject m_promise;
private Thread m_thread;
private ResultBuilderContext m_builderContext;
private ResultBuilder m_resultBuilder;
private ExecutorInstance(Context context, JavaScriptPromiseObject promise,
ResultBuilder resultBuilder)
{
this.m_context = context;
this.m_promise = promise;
this.m_resultBuilder = resultBuilder;
}
public Context context() {
return m_context;
}
public JavaScriptPromiseObject promise() {
return m_promise;
}
public Thread thread() {
return m_thread;
}
public ResultBuilderContext builderContext() {
return m_builderContext;
}
public ResultBuilder resultBuilder() {
return m_resultBuilder;
}
}
/**
*
* @param context
* @param executor
* @param resultBuilder
* @return
*/
public ExecutorInstance startWorker(Context context, Executor executor, ResultBuilder resultBuilder)
{
if (Thread.currentThread() != m_javaScriptThread) {
throw new RuntimeException("You should call this function on JavaScriptThread");
}
if (context == null || executor == null || resultBuilder == null) {
throw new NullPointerException();
}
JavaScriptPromiseObject promise = JavaScriptPromiseObject.create(context);
ExecutorInstance instance = new ExecutorInstance(context, promise, resultBuilder);
class ExecutorRunnable implements Runnable {
@Override
public void run() {
instance.m_builderContext = executor.run();
if (instance.m_builderContext == null) {
throw new NullPointerException();
}
synchronized (m_endedInstances) {
m_endedInstances.add(instance);
}
synchronized (m_activeInstances) {
m_activeInstances.remove(instance);
}
m_workerThreadEndNotifier.notify(MultiThreadExecutor.this, instance);
}
}
Thread thread = new Thread(new ExecutorRunnable());
instance.m_thread = thread;
synchronized (m_activeInstances) {
m_activeInstances.add(instance);
}
thread.start();
return instance;
}
public boolean hasPendingEvent()
{
synchronized (m_endedInstances) {
return !m_endedInstances.isEmpty();
}
}
public boolean hasPendingWorker()
{
synchronized (m_activeInstances) {
return !m_activeInstances.isEmpty();
}
}
public boolean hasPendingEventOrWorker()
{
return hasPendingWorker() || hasPendingEvent();
}
/**
* must call this function from main thread(JS thread)
*/
public void pumpEventsFromThreadIfNeeds(boolean executePendingJavaScriptJobs)
{
if (Thread.currentThread() != m_javaScriptThread) {
throw new RuntimeException("You should call this function on JavaScriptThread");
}
Object[] instances;
synchronized (m_endedInstances) {
instances = m_endedInstances.toArray();
m_endedInstances.clear();
}
for (int i = 0; i < instances.length; i ++) {
ExecutorInstance e = (ExecutorInstance)instances[i];
JavaScriptValue value = e.resultBuilder().build(e.context(), e.builderContext());
if (e.builderContext().wasSuccessful()) {
e.promise().fulfill(e.context(), value);
} else {
e.promise().reject(e.context(), value);
}
}
if (executePendingJavaScriptJobs) {
m_vmInstance.executeEveryPendingJobIfExists();
}
}
/**
* must call this function from main thread(JS thread)
*/
public void pumpEventsFromThreadIfNeeds()
{
pumpEventsFromThreadIfNeeds(true);
}
}

View file

@ -1,6 +1,6 @@
#Fri May 30 15:07:57 KST 2025
#Wed Jan 25 15:38:01 KST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View file

@ -1 +0,0 @@
./gradlew publish

View file

@ -1,2 +0,0 @@
./gradlew bundleHostJar
MAVEN_OPTS="-Dmaven.repo.local=${MAVEN_LOCAL_PATH}/mac/releases/" mvn install:install-file -Dfile=${PWD}/escargot/build/libs/escargot.jar -DgroupId=com.samsung.lwe.escargot -DartifactId=escargot-mac -Dversion=X.X.X.20XXXXXX.X.XXXXXXX -Dpackaging=jar

View file

@ -1,2 +0,0 @@
./gradlew bundleHostJar
MAVEN_OPTS="-Dmaven.repo.local=${MAVEN_LOCAL_PATH}/ubuntu/releases/" mvn install:install-file -Dfile=${PWD}/escargot/build/libs/escargot.jar -DgroupId=com.samsung.lwe.escargot -DartifactId=escargot-ubuntu -Dversion=X.X.X.20XXXXXX.X.XXXXXXX -Dpackaging=jar

View file

@ -3,9 +3,6 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.8.12 FATAL_ERROR)
#######################################################
# CONFIGURATION
#######################################################
SET (ESCARGOT_LIBRARIES)
SET (ESCARGOT_INCDIRS)
# CONFIGURE ESCARGOT VERSION
FIND_PACKAGE(Git)
IF (GIT_FOUND)
@ -20,8 +17,7 @@ IF ((NOT DEFINED ESCARGOT_BUILD_VERSION) OR (ESCARGOT_BUILD_VERSION STREQUAL "")
FILE (STRINGS "${PROJECT_SOURCE_DIR}/RELEASE_VERSION" ESCARGOT_BUILD_VERSION)
ENDIF()
MESSAGE(STATUS "Escargot Build Version: ${ESCARGOT_BUILD_VERSION}")
CONFIGURE_FILE (${PROJECT_SOURCE_DIR}/src/EscargotInfo.h.in ${CMAKE_BINARY_DIR}/escargot_generated/EscargotInfo.h @ONLY)
SET (ESCARGOT_INCDIRS ${ESCARGOT_INCDIRS} ${CMAKE_BINARY_DIR}/escargot_generated)
CONFIGURE_FILE (${PROJECT_SOURCE_DIR}/src/EscargotInfo.h.in ${PROJECT_SOURCE_DIR}/src/EscargotInfo.h @ONLY)
#######################################################
# PATH
@ -33,6 +29,8 @@ SET (GCUTIL_ROOT ${ESCARGOT_THIRD_PARTY_ROOT}/GCutil)
#######################################################
# FLAGS FOR TARGET
#######################################################
SET (ESCARGOT_LIBRARIES)
SET (ESCARGOT_INCDIRS)
INCLUDE (${ESCARGOT_ROOT}/build/target.cmake)
#######################################################
@ -48,14 +46,14 @@ SET (CXXFLAGS_FROM_ENV $ENV{CXXFLAGS})
SEPARATE_ARGUMENTS(CXXFLAGS_FROM_ENV)
SET (CFLAGS_FROM_ENV $ENV{CFLAGS})
SEPARATE_ARGUMENTS(CFLAGS_FROM_ENV)
SET (ESCARGOT_CXXFLAGS
${CXXFLAGS_FROM_ENV}
${ESCARGOT_CXXFLAGS})
SET (LDFLAGS_FROM_ENV $ENV{LDFLAGS})
SEPARATE_ARGUMENTS(LDFLAGS_FROM_ENV)
# these flags assigned from external should have the highest priority
SET (CXXFLAGS_FROM_ENV ${CXXFLAGS_FROM_ENV} ${ESCARGOT_CXXFLAGS_FROM_EXTERNAL})
SET (CFLAGS_FROM_ENV ${CFLAGS_FROM_ENV} ${ESCARGOT_CFLAGS_FROM_EXTERNAL})
SET (LDFLAGS_FROM_ENV ${LDFLAGS_FROM_ENV} ${ESCARGOT_LDFLAGS_FROM_EXTERNAL})
# ESCARGOT COMMON LDFLAGS
SET (ESCARGOT_LDFLAGS ${ESCARGOT_LDFLAGS} -fvisibility=hidden)
@ -73,48 +71,43 @@ IF (ESCARGOT_SMALL_CONFIG)
ENDIF()
IF (NOT DEFINED ESCARGOT_LIBICU_SUPPORT)
SET (ESCARGOT_LIBICU_SUPPORT ON)
SET (ESCARGOT_LIBICU_SUPPORT OFF)
ENDIF()
IF (NOT DEFINED ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN)
SET (ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN ON)
SET (ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN OFF)
ENDIF()
#######################################################
# FLAGS FOR ADDITIONAL FUNCTION
#######################################################
IF (ESCARGOT_LIBICU_SUPPORT)
IF (ESCARGOT_DEPLOY)
# Build for deployment (include ICU library)
SET (CMAKE_INSTALL_RPATH "$ORIGIN")
SET (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
ENDIF()
IF (ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_ICU -DENABLE_INTL -DENABLE_RUNTIME_ICU_BINDER)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_DISPLAYNAMES -DENABLE_INTL_NUMBERFORMAT -DENABLE_INTL_PLURALRULES)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_RELATIVETIMEFORMAT -DENABLE_INTL_LISTFORMAT -DENABLE_INTL_DURATIONFORMAT)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_SEGMENTER)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_RELATIVETIMEFORMAT -DENABLE_INTL_LISTFORMAT)
ELSE()
IF (NOT ${ESCARGOT_HOST} STREQUAL "windows")
# windows icu cannot support these feature yet.(~10.0.18362)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_DISPLAYNAMES -DENABLE_INTL_NUMBERFORMAT -DENABLE_INTL_PLURALRULES)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_RELATIVETIMEFORMAT -DENABLE_INTL_LISTFORMAT -DENABLE_INTL_DURATIONFORMAT)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_SEGMENTER)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_INTL_RELATIVETIMEFORMAT -DENABLE_INTL_LISTFORMAT)
PKG_CHECK_MODULES(ICU REQUIRED icu-uc icu-i18n)
PKG_CHECK_MODULES (ICUI18N REQUIRED icu-i18n)
PKG_CHECK_MODULES (ICUUC REQUIRED icu-uc)
ENDIF()
MESSAGE(STATUS "ICU Libraries: ${ICU_LIBRARIES}")
SET (ESCARGOT_LDFLAGS ${ESCARGOT_LDFLAGS} ${ICU_LDFLAGS})
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_ICU -DENABLE_INTL)
SET (ESCARGOT_INCDIRS ${ESCARGOT_INCDIRS} ${ICU_INCLUDE_DIRS})
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} ${ICU_LIBRARIES})
ENDIF()
ENDIF()
IF (ESCARGOT_USE_EXTENDED_API)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_EXTENDED_API)
IF (${ESCARGOT_HOST} STREQUAL "darwin")
FOREACH (ICU_LDFLAG ${ICUI18N_LDFLAGS} ${ICUUC_LDFLAGS})
SET (ESCARGOT_LDFLAGS ${ESCARGOT_LDFLAGS} ${ICU_LDFLAG})
ENDFOREACH()
ELSE()
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} ${ICUI18N_LIBRARIES} ${ICUUC_LIBRARIES})
ENDIF()
SET (ESCARGOT_INCDIRS ${ESCARGOT_INCDIRS} ${ICUI18N_INCLUDE_DIRS} ${ICUUC_INCLUDE_DIRS})
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} ${ICUI18N_CFLAGS_OTHER} ${ICUUC_CFLAGS_OTHER})
ENDIF()
ENDIF()
IF (ESCARGOT_USE_CUSTOM_LOGGING)
@ -139,10 +132,6 @@ ENDIF()
IF (ESCARGOT_WASM)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_WASM)
IF (NOT DEFINED ESCARGOT_THREADING)
# threading should be enabled for WASM (WASM threading feature)
SET (ESCARGOT_THREADING ON)
ENDIF()
ENDIF()
IF (ESCARGOT_THREADING)
@ -155,40 +144,14 @@ ENDIF()
IF (ESCARGOT_TCO)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_TCO)
IF (ESCARGOT_TCO_DEBUG)
IF (NOT ${ESCARGOT_MODE} STREQUAL "debug")
MESSAGE (FATAL_ERROR "ESCARGOT_TCO_DEBUG is enabled only for debug mode")
ENDIF()
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_TCO_DEBUG)
ENDIF()
ENDIF()
IF (ESCARGOT_TEMPORAL)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_TEMPORAL)
IF (NOT ESCARGOT_LIBICU_SUPPORT)
MESSAGE (FATAL_ERROR "Temporal feature needs ICU")
ENDIF()
ENDIF()
IF (ESCARGOT_SHADOWREALM)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_SHADOWREALM)
ENDIF()
IF (ESCARGOT_TLS_ACCESS_BY_ADDRESS)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_TLS_ACCESS_BY_ADDRESS)
ENDIF()
IF (ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_TLS_ACCESS_BY_PTHREAD_KEY)
ENDIF()
IF (ESCARGOT_TEST)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DESCARGOT_ENABLE_TEST)
IF (ESCARGOT_CODE_CACHE)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DCODE_CACHE_MIN_SOURCE_LENGTH=1024)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DCODE_CACHE_MAX_CACHE_COUNT=128)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DCODE_CACHE_SHOULD_LOAD_FUNCTIONS_ON_SCRIPT_LOADING=true)
ENDIF()
ENDIF()
#######################################################
@ -211,7 +174,7 @@ SET (ESCARGOT_CXXFLAGS_STATICLIB -fPIC -DESCARGOT_EXPORT=)
SET (ESCARGOT_CXXFLAGS_SHELL -DESCARGOT_EXPORT=)
#######################################################
# FLAGS FOR PROFILING
# FLAGS FOR MEMORY PROFILING
#######################################################
SET (PROFILER_FLAGS)
@ -227,11 +190,6 @@ IF (ESCARGOT_VALGRIND)
SET (PROFILER_FLAGS ${PROFILER_FLAGS} -DESCARGOT_VALGRIND)
ENDIF()
IF (ESARGOT_GOOGLE_PERF)
SET (PROFILER_FLAGS ${PROFILER_FLAGS} -DESCARGOT_GOOGLE_PERF)
SET (ESCARGOT_LDFLAGS ${ESCARGOT_LDFLAGS} -lprofiler -lunwind -llzma)
ENDIF()
#######################################################
# FLAGS FOR DEBUGGER
#######################################################

View file

@ -3,15 +3,12 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.8.12 FATAL_ERROR)
SET (ESCARGOT_INCDIRS
${ESCARGOT_INCDIRS}
${ESCARGOT_ROOT}/src/
${ESCARGOT_THIRD_PARTY_ROOT}
${ESCARGOT_THIRD_PARTY_ROOT}/checked_arithmetic/
${ESCARGOT_THIRD_PARTY_ROOT}/double_conversion/
${ESCARGOT_THIRD_PARTY_ROOT}/lz4/
${ESCARGOT_THIRD_PARTY_ROOT}/rapidjson/include/
${ESCARGOT_THIRD_PARTY_ROOT}/yarr/
${ESCARGOT_THIRD_PARTY_ROOT}/runtime_icu_binder/
${ESCARGOT_THIRD_PARTY_ROOT}/robin_map/include/
${ESCARGOT_THIRD_PARTY_ROOT}/xsum/
)
IF (${ESCARGOT_MODE} STREQUAL "debug")
@ -55,7 +52,6 @@ FILE (GLOB_RECURSE ESCARGOT_SRC ${ESCARGOT_ROOT}/src/*.cpp)
FILE (GLOB YARR_SRC ${ESCARGOT_THIRD_PARTY_ROOT}/yarr/*.cpp)
FILE (GLOB DOUBLE_CONVERSION_SRC ${ESCARGOT_THIRD_PARTY_ROOT}/double_conversion/*.cc)
FILE (GLOB LZ4_SRC ${ESCARGOT_THIRD_PARTY_ROOT}/lz4/*.cpp)
FILE (GLOB XSUM_SRC ${ESCARGOT_THIRD_PARTY_ROOT}/xsum/*.cpp)
IF (NOT ${ESCARGOT_OUTPUT} MATCHES "shell")
LIST (REMOVE_ITEM ESCARGOT_SRC ${ESCARGOT_ROOT}/src/shell/Shell.cpp)
@ -74,83 +70,39 @@ SET (ESCARGOT_SRC_LIST
${YARR_SRC}
${DOUBLE_CONVERSION_SRC}
${LZ4_SRC}
${XSUM_SRC}
${CCTEST_SRC}
)
#######################################################
# GCUTIL
#######################################################
IF (${ESCARGOT_OUTPUT} STREQUAL "shared_lib")
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} ${ESCARGOT_CXXFLAGS_SHAREDLIB})
ELSEIF (${ESCARGOT_OUTPUT} STREQUAL "static_lib")
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} ${ESCARGOT_CXXFLAGS_STATICLIB})
ENDIF()
SET (GCUTIL_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} ${PROFILER_FLAGS})
SET (GCUTIL_CFLAGS_FROM_EXTERNAL ${ESCARGOT_CFLAGS_FROM_EXTERNAL})
SET (GCUTIL_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS})
IF (ESCARGOT_SMALL_CONFIG)
SET (GCUTIL_CFLAGS ${GCUTIL_CFLAGS} -DSMALL_CONFIG)
SET (GCUTIL_CFLAGS ${GCUTIL_CFLAGS} -DSMALL_CONFIG -DMAX_HEAP_SECTS=512)
ENDIF()
IF (ESCARGOT_THREADING)
SET (GCUTIL_ENABLE_THREADING ON)
ENDIF()
IF (ESCARGOT_TLS_ACCESS_BY_ADDRESS)
SET (GCUTIL_ENABLE_TLS_ACCESS_BY_ADDRESS ON)
ENDIF()
IF (ESCARGOT_TLS_ACCESS_BY_PTHREAD_KEY)
SET (GCUTIL_ENABLE_TLS_ACCESS_BY_PTHREAD_KEY ON)
ENDIF()
SET (GCUTIL_MODE ${ESCARGOT_MODE})
ADD_SUBDIRECTORY (third_party/GCutil)
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} gc-lib)
#######################################################
# SIMDUTF
#######################################################
ADD_LIBRARY (libsimdutf STATIC
${ESCARGOT_THIRD_PARTY_ROOT}/simdutf/simdutf.cpp)
TARGET_INCLUDE_DIRECTORIES (libsimdutf PUBLIC ${ESCARGOT_THIRD_PARTY_ROOT}/simdutf)
SET (LIBSIMDUTF_CXXFLAGS
${ESCARGOT_CXXFLAGS}
${ESCARGOT_THIRDPARTY_CFLAGS}
${CXXFLAGS_FROM_ENV}
# disable simd optimization
-DSIMDUTF_IMPLEMENTATION_ARM64=0
-DSIMDUTF_IMPLEMENTATION_ICELAKE=0
-DSIMDUTF_IMPLEMENTATION_HASWELL=0
-DSIMDUTF_IMPLEMENTATION_WESTMERE=0
-DSIMDUTF_IMPLEMENTATION_PPC64=0
-DSIMDUTF_IMPLEMENTATION_RVV=0
-DSIMDUTF_IMPLEMENTATION_LSX=0
-DSIMDUTF_IMPLEMENTATION_FALLBACK=1
# ${ESCARGOT_CXXFLAGS_FROM_EXTERNAL} already included in ${CXXFLAGS_FROM_ENV}
)
IF (${ESCARGOT_MODE} STREQUAL "debug")
SET (LIBSIMDUTF_CXXFLAGS ${ESCARGOT_CXXFLAGS_DEBUG} ${LIBSIMDUTF_CXXFLAGS})
ELSEIF (${ESCARGOT_MODE} STREQUAL "release")
SET (LIBSIMDUTF_CXXFLAGS ${ESCARGOT_CXXFLAGS_RELEASE} ${LIBSIMDUTF_CXXFLAGS})
ENDIF()
TARGET_COMPILE_OPTIONS (libsimdutf PRIVATE ${LIBSIMDUTF_CXXFLAGS})
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} libsimdutf)
#######################################################
# LIBBF
#######################################################
ADD_LIBRARY (libbf STATIC
${ESCARGOT_THIRD_PARTY_ROOT}/libbf/libbf.c
${ESCARGOT_THIRD_PARTY_ROOT}/libbf/cutils.c)
TARGET_INCLUDE_DIRECTORIES (libbf PUBLIC ${ESCARGOT_THIRD_PARTY_ROOT}/libbf)
SET (LIBBF_CFLAGS
${ESCARGOT_THIRDPARTY_CFLAGS}
${ESCARGOT_THIRDPARTY_CFLAGS} # we can share flags with gcutil
${CFLAGS_FROM_ENV}
# ${ESCARGOT_CFLAGS_FROM_EXTERNAL} already included in ${CFLAGS_FROM_ENV}
)
IF (${ESCARGOT_MODE} STREQUAL "debug")
@ -163,157 +115,42 @@ TARGET_COMPILE_OPTIONS (libbf PRIVATE ${LIBBF_CFLAGS})
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} libbf)
#######################################################
# RUNTIME ICU BINDER
#######################################################
SET (RIB_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS})
SET (RIB_MODE ${ESCARGOT_MODE})
SET (RIB_CFLAGS_FROM_EXTERNAL ${ESCARGOT_CFLAGS_FROM_EXTERNAL})
ADD_SUBDIRECTORY (third_party/runtime_icu_binder)
# ROBIN MAP
ADD_SUBDIRECTORY(third_party/robin_map)
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} tsl::robin_map)
IF (ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN)
# RUNTIME ICU BINDER
SET (RIB_CFLAGS ${ESCARGOT_CXXFLAGS})
IF (${ESCARGOT_OUTPUT} STREQUAL "shared_lib")
SET (RIB_CFLAGS ${RIB_CFLAGS} ${ESCARGOT_CXXFLAGS_SHAREDLIB})
ELSEIF (${ESCARGOT_OUTPUT} STREQUAL "static_lib")
SET (RIB_CFLAGS ${RIB_CFLAGS} ${ESCARGOT_CXXFLAGS_STATICLIB})
ENDIF()
SET (RIB_MODE ${ESCARGOT_MODE})
ADD_SUBDIRECTORY (third_party/runtime_icu_binder)
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} runtime-icu-binder-static)
ENDIF()
#######################################################
# WebAssembly (walrus)
#######################################################
# WebAssembly (wabt)
IF (ESCARGOT_WASM)
SET (WALRUS_CXXFLAGS
${ESCARGOT_THIRDPARTY_CFLAGS}
-g3)
SET (WASM_CXX_FLAGS
${ESCARGOT_THIRDPARTY_CFLAGS} # we can share flags with gcutil
)
SET (WASM_ARCH ${ESCARGOT_ARCH})
SET (WALRUS_HOST ${ESCARGOT_HOST})
SET (WALRUS_ARCH ${ESCARGOT_ARCH})
SET (WALRUS_MODE ${ESCARGOT_MODE})
SET (WALRUS_OUTPUT "shared_lib")
SET (WALRUS_WASI OFF) # WASI should be OFF
SET (WALRUS_EXTENDED_FEATURES ON) # enable extended features
IF (${ESCARGOT_MODE} STREQUAL "release")
SET (WALRUS_CXXFLAGS ${WALRUS_CXXFLAGS} ${ESCARGOT_CXXFLAGS_RELEASE})
SET (WASM_CXX_FLAGS ${WASM_CXX_FLAGS} ${ESCARGOT_CXXFLAGS_RELEASE})
ENDIF()
SET (WALRUS_CXXFLAGS_FROM_EXTERNAL ${ESCARGOT_CXXFLAGS_FROM_EXTERNAL})
SET (WALRUS_LDFLAGS_FROM_EXTERNAL ${ESCARGOT_LDFLAGS_FROM_EXTERNAL})
ADD_SUBDIRECTORY (third_party/walrus)
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} walrus)
ADD_SUBDIRECTORY (third_party/wasm)
SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} wasm)
ENDIF()
MAKE_DIRECTORY(${CMAKE_BINARY_DIR}/escargot_generated/tmp)
# Generate UnicodeIdentifierTables.cpp
MAKE_DIRECTORY(${CMAKE_BINARY_DIR}/escargot_generated/parser)
EXECUTE_PROCESS(
COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/code_generators/gen_unicode.py --derived_core_properties ${PROJECT_SOURCE_DIR}/tools/unicode_data/DerivedCoreProperties.txt --dst ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodeIdentifierTables.cpp
RESULT_VARIABLE GENERATE_RESULT
OUTPUT_VARIABLE GENERATE_OUTPUT
ERROR_VARIABLE GENERATE_ERROR
)
IF (NOT GENERATE_RESULT EQUAL 0)
MESSAGE(STATUS "Output:\n${GENERATE_OUTPUT}")
MESSAGE(FATAL_ERROR "${GENERATE_ERROR}")
ENDIF()
EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodeIdentifierTables.cpp ${CMAKE_BINARY_DIR}/escargot_generated/parser/UnicodeIdentifierTables.cpp
RESULT_VARIABLE COMPARE_RESULT
OUTPUT_VARIABLE COMPARE_OUTPUT
ERROR_VARIABLE COMPARE_ERROR
)
IF (NOT ${COMPARE_RESULT} EQUAL 0)
FILE (COPY ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodeIdentifierTables.cpp DESTINATION ${CMAKE_BINARY_DIR}/escargot_generated/parser/)
ENDIF()
SET (ESCARGOT_SRC_LIST ${ESCARGOT_SRC_LIST} ${CMAKE_BINARY_DIR}/escargot_generated/parser/UnicodeIdentifierTables.cpp)
# Generate YarrCanonicalizeUnicode.cpp
MAKE_DIRECTORY(${CMAKE_BINARY_DIR}/escargot_generated/yarr)
EXECUTE_PROCESS(
COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/code_generators/generateYarrCanonicalizeUnicode.py ${PROJECT_SOURCE_DIR}/tools/unicode_data/CaseFolding.txt ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUnicode.cpp
RESULT_VARIABLE GENERATE_RESULT
OUTPUT_VARIABLE GENERATE_OUTPUT
ERROR_VARIABLE GENERATE_ERROR
)
IF (NOT GENERATE_RESULT EQUAL 0)
MESSAGE(STATUS "Output:\n${GENERATE_OUTPUT}")
MESSAGE(FATAL_ERROR "${GENERATE_ERROR}")
ENDIF()
FILE(READ ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUnicode.cpp UNICODE_FILE_CONTENTS)
STRING(REPLACE "config.h" "WTFBridge.h" UNICODE_FILE_CONTENTS "${UNICODE_FILE_CONTENTS}")
STRING(REPLACE "constexpr const" "const" UNICODE_FILE_CONTENTS "${UNICODE_FILE_CONTENTS}")
STRING(REPLACE "constexpr size_t UNICODE" "const size_t UNICODE" UNICODE_FILE_CONTENTS "${UNICODE_FILE_CONTENTS}")
STRING(REPLACE "constexpr CanonicalizationRange unicodeRangeInfo" "const CanonicalizationRange unicodeRangeInfo" UNICODE_FILE_CONTENTS "${UNICODE_FILE_CONTENTS}")
FILE(WRITE ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUnicode.cpp "${UNICODE_FILE_CONTENTS}")
EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUnicode.cpp ${CMAKE_BINARY_DIR}/escargot_generated/yarr/YarrCanonicalizeUnicode.cpp
RESULT_VARIABLE COMPARE_RESULT
OUTPUT_VARIABLE COMPARE_OUTPUT
ERROR_VARIABLE COMPARE_ERROR
)
IF (NOT ${COMPARE_RESULT} EQUAL 0)
FILE (COPY ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUnicode.cpp DESTINATION ${CMAKE_BINARY_DIR}/escargot_generated/yarr/)
ENDIF()
SET(ESCARGOT_SRC_LIST ${ESCARGOT_SRC_LIST} ${CMAKE_BINARY_DIR}/escargot_generated/yarr/YarrCanonicalizeUnicode.cpp)
# yarr/UnicodePatternTables.h
EXECUTE_PROCESS(
COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/code_generators/generateYarrUnicodePropertyTables.py ${PROJECT_SOURCE_DIR}/tools/unicode_data ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodePatternTables.h
RESULT_VARIABLE GENERATE_RESULT
OUTPUT_VARIABLE GENERATE_OUTPUT
ERROR_VARIABLE GENERATE_ERROR
)
IF (NOT GENERATE_RESULT EQUAL 0)
MESSAGE(STATUS "Output:\n${GENERATE_OUTPUT}")
MESSAGE(FATAL_ERROR "${GENERATE_ERROR}")
ENDIF()
EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodePatternTables.h ${CMAKE_BINARY_DIR}/escargot_generated/yarr/UnicodePatternTables.h
RESULT_VARIABLE COMPARE_RESULT
OUTPUT_VARIABLE COMPARE_OUTPUT
ERROR_VARIABLE COMPARE_ERROR
)
IF (NOT ${COMPARE_RESULT} EQUAL 0)
FILE (COPY ${CMAKE_BINARY_DIR}/escargot_generated/tmp/UnicodePatternTables.h DESTINATION ${CMAKE_BINARY_DIR}/escargot_generated/yarr/)
ENDIF()
SET (ESCARGOT_INCDIRS
${ESCARGOT_INCDIRS}
${CMAKE_BINARY_DIR}/escargot_generated/yarr/
)
# YarrCanonicalizeUCS2.cpp
EXECUTE_PROCESS(
COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/code_generators/generateYarrCanonicalizeUCS2.py ${PROJECT_SOURCE_DIR}/tools/unicode_data/UnicodeData.txt ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUCS2.cpp
RESULT_VARIABLE GENERATE_RESULT
OUTPUT_VARIABLE GENERATE_OUTPUT
ERROR_VARIABLE GENERATE_ERROR
)
IF (NOT GENERATE_RESULT EQUAL 0)
MESSAGE(STATUS "Output:\n${GENERATE_OUTPUT}")
MESSAGE(FATAL_ERROR "${GENERATE_ERROR}")
ENDIF()
EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUCS2.cpp ${CMAKE_BINARY_DIR}/escargot_generated/yarr/YarrCanonicalizeUCS2.cpp
RESULT_VARIABLE COMPARE_RESULT
OUTPUT_VARIABLE COMPARE_OUTPUT
ERROR_VARIABLE COMPARE_ERROR
)
IF (NOT ${COMPARE_RESULT} EQUAL 0)
FILE (COPY ${CMAKE_BINARY_DIR}/escargot_generated/tmp/YarrCanonicalizeUCS2.cpp DESTINATION ${CMAKE_BINARY_DIR}/escargot_generated/yarr/)
ENDIF()
SET(ESCARGOT_SRC_LIST ${ESCARGOT_SRC_LIST} ${CMAKE_BINARY_DIR}/escargot_generated/yarr/YarrCanonicalizeUCS2.cpp)
# BUILD
IF (${ESCARGOT_OUTPUT} STREQUAL "shell")
ADD_EXECUTABLE (${ESCARGOT_TARGET} ${ESCARGOT_SRC_LIST})

View file

@ -9,15 +9,12 @@ SET (ESCARGOT_THIRDPARTY_CFLAGS)
SET (ESCARGOT_BUILD_32BIT OFF)
SET (ESCARGOT_BUILD_64BIT OFF)
SET (ESCARGOT_BUILD_64BIT_LARGE OFF)
IF (ESCARGOT_ASAN)
SET (ESCARGOT_BUILD_64BIT_LARGE ON)
ENDIF()
# clang-cl defines ${CMAKE_CXX_COMPILER_ID} "Clang" and ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} "MSVC"
SET (COMPILER_CLANG_CL OFF)
IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
IF (DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT)
IF ("${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC")
IF (${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL "MSVC")
SET (COMPILER_CLANG_CL ON)
ENDIF()
ENDIF()
@ -25,18 +22,13 @@ ENDIF()
# Default options per compiler
IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" OR ${COMPILER_CLANG_CL})
SET (ESCARGOT_COMPILER_ID "MSVC")
SET (ESCARGOT_CXXFLAGS /std:c++17 /fp:strict /Zc:__cplusplus /EHs /source-charset:utf-8 /MP /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING /wd4244 /wd4267 /wd4805 /wd4018 /wd4172 /wd4146)
SET (ESCARGOT_CXXFLAGS /std:c++17 /fp:strict /Zc:__cplusplus /EHs /source-charset:utf-8 /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING /wd4244 /wd4267 /wd4805 /wd4018 /wd4172)
SET (ESCARGOT_CXXFLAGS_RELEASE /O2 /Oy-)
SET (ESCARGOT_THIRDPARTY_CFLAGS /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /Oy- /wd4146 /EHs)
IF (${COMPILER_CLANG_CL})
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} /EHs -Wno-invalid-offsetof -Wno-inline-new-delete -fintegrated-cc1)
ENDIF()
IF (ESCARGOT_SMALL_CONFIG)
SET (ESCARGOT_CXXFLAGS_RELEASE ${ESCARGOT_CXXFLAGS_RELEASE} /Os)
ENDIF()
ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
SET (ESCARGOT_COMPILER_ID "GCC")
SET (ESCARGOT_CXXFLAGS
${ESCARGOT_CXXFLAGS}
-std=c++11 -g3
@ -51,26 +43,13 @@ ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
-Wno-unused-but-set-variable -Wno-unused-but-set-parameter
-Wno-deprecated-declarations -Wno-unused-function
)
IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16)
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} -Wno-maybe-uninitialized)
ENDIF()
IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9)
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} -Wno-attributes -Wno-class-memaccess -Wno-deprecated-copy -Wno-cast-function-type -Wno-stringop-truncation -Wno-pessimizing-move -Wno-mismatched-new-delete -Wno-overloaded-virtual -Wno-dangling-pointer)
endif()
SET (ESCARGOT_CXXFLAGS_DEBUG -O0 -Wall -Wextra -Werror)
SET (ESCARGOT_CXXFLAGS_RELEASE -O2 -fno-stack-protector -fno-omit-frame-pointer)
IF (ESCARGOT_SMALL_CONFIG)
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 9)
# BUG?) -Os option has unknown memory conflicts (might be related with gcc version)
# enable this option only for old gcc version
SET (ESCARGOT_CXXFLAGS_RELEASE ${ESCARGOT_CXXFLAGS_RELEASE} -Os)
ENDIF()
ENDIF()
SET (ESCARGOT_THIRDPARTY_CFLAGS -w -g3 -fdata-sections -ffunction-sections -fno-omit-frame-pointer -fvisibility=hidden)
ELSEIF (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") #include Clang and AppleClang both
SET (ESCARGOT_COMPILER_ID "CLANG")
ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
SET (ESCARGOT_CXXFLAGS
${ESCARGOT_CXXFLAGS}
-std=c++11 -g3
@ -81,20 +60,12 @@ ELSEIF (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") #include Clang and AppleClang
-fvisibility=hidden
-fno-fast-math -fno-unsafe-math-optimizations -fdenormal-fp-math=ieee
-Wno-type-limits -Wno-unused-result -Wno-unused-variable -Wno-invalid-offsetof -Wno-unused-function
-Wno-deprecated-declarations -Wno-parentheses-equality -Wno-dynamic-class-memaccess -Wno-deprecated-register
-Wno-deprecated-declarations -Wno-unsupported-floating-point-opt -Wno-parentheses-equality -Wno-dynamic-class-memaccess -Wno-deprecated-register
-Wno-expansion-to-defined -Wno-return-type -Wno-overloaded-virtual -Wno-unused-private-field -Wno-deprecated-copy -Wno-atomic-alignment
-Wno-ambiguous-reversed-operator -Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion -Wno-braced-scalar-init -Wno-unused-parameter -Wno-deprecated-literal-operator -Wno-cast-function-type-mismatch
-Wno-unknown-warning-option
-Wno-ambiguous-reversed-operator -Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion -Wno-braced-scalar-init -Wno-unused-parameter
)
IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10)
# this feature supported after clang version 11
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} -Wno-unsupported-floating-point-opt)
endif()
SET (ESCARGOT_CXXFLAGS_DEBUG -O0 -Wall -Wextra -Werror)
SET (ESCARGOT_CXXFLAGS_RELEASE -O2 -fno-stack-protector -fno-omit-frame-pointer)
IF (ESCARGOT_SMALL_CONFIG)
SET (ESCARGOT_CXXFLAGS_RELEASE ${ESCARGOT_CXXFLAGS_RELEASE} -Os)
ENDIF()
SET (ESCARGOT_THIRDPARTY_CFLAGS -w -g3 -fdata-sections -ffunction-sections -fno-omit-frame-pointer -fvisibility=hidden)
ELSE()
MESSAGE (FATAL_ERROR ${CMAKE_CXX_COMPILER_ID} " is Unsupported Compiler")
@ -177,23 +148,15 @@ ELSEIF (${ESCARGOT_HOST} STREQUAL "android")
# bdwgc android amd64 cannot support keeping back ptrs
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} -UKEEP_BACK_PTRS -USAVE_CALL_COUNT -UDBG_HDRS_ALL)
ENDIF()
ELSEIF (${ESCARGOT_HOST} STREQUAL "darwin")
ELSEIF (${ESCARGOT_HOST} STREQUAL "darwin" AND ${ESCARGOT_ARCH} STREQUAL "x64")
FIND_PACKAGE (PkgConfig REQUIRED)
IF ((NOT ${ESCARGOT_ARCH} STREQUAL "x64") AND (NOT ${ESCARGOT_ARCH} STREQUAL "aarch64"))
MESSAGE (FATAL_ERROR ${ESCARGOT_ARCH} " is unsupported")
ENDIF()
# recent macOS supports only ICU version 75 that requires c++17 or above
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} -std=c++17)
SET (ESCARGOT_LDFLAGS -lpthread -Wl,-dead_strip)
SET (ESCARGOT_BUILD_64BIT_LARGE ON)
# bdwgc mac cannot support pthread_getattr_np
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} -UHAVE_PTHREAD_GETATTR_NP)
# dlopen version not working correctly on mac
IF (NOT DEFINED ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN)
SET (ESCARGOT_LIBICU_SUPPORT_WITH_DLOPEN OFF)
ENDIF()
ELSEIF (${ESCARGOT_HOST} STREQUAL "windows")
SET (ESCARGOT_LDFLAGS ${ESCARGOT_LDFLAGS} icu.lib)
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} -DSTACK_LIMIT_FROM_BASE=1048576) # in windows, default stack limit is 1MB
IF ((${ESCARGOT_ARCH} STREQUAL "x64") OR (${ESCARGOT_ARCH} STREQUAL "x86_64"))
SET (ESCARGOT_BUILD_64BIT ON)
SET (ESCARGOT_BUILD_64BIT_LARGE ON)

View file

@ -1,10 +0,0 @@
coverage:
status:
project:
default:
target: 80%
threshold: 1%
ignore:
- "third_party"
- "src/api"

View file

@ -115,15 +115,9 @@ Requires(postun): /sbin/ldconfig
%define enable_shell 0
%endif
%if 0%{?enable_small_config:1}
%else
%define enable_small_config 0
%endif
# build requirements
BuildRequires: cmake
BuildRequires: ninja
BuildRequires: python3
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(bundle)
@ -260,17 +254,14 @@ CFLAGS+=' -Os '
CXXFLAGS+=' -Os '
%endif
CFLAGS+=' -Wno-shadow '
CXXFLAGS+=' -Wno-shadow '
%if "%{?enable_test}" == "1"
cmake CMakeLists.txt -H./ -Bbuild/out_tizen_%{rpm} -DLIBDIR=%{_libdir} -DINCLUDEDIR=%{_includedir} -DTIZEN_MAJOR_VERSION='%{tizen_version_major}' \
-DESCARGOT_ARCH='%{tizen_arch}' -DESCARGOT_WASM='%{enable_wasm}' -DESCARGOT_DEBUGGER='%{enable_debugger}' -DESCARGOT_SMALL_CONFIG='%{enable_small_config}' \
-DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_MODE=release -DESCARGOT_HOST=tizen -DESCARGOT_OUTPUT=shared_lib -DESCARGOT_TEST=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -G Ninja
-DESCARGOT_ARCH='%{tizen_arch}' -DESCARGOT_WASM='%{enable_wasm}' -DESCARGOT_DEBUGGER='%{enable_debugger}' \
-DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON -DESCARGOT_MODE=release -DESCARGOT_HOST=tizen -DESCARGOT_OUTPUT=shared_lib -DESCARGOT_TEST=ON -DESCARGOT_TEMPORAL=ON -DESCARGOT_TCO=ON -G Ninja
%else
cmake CMakeLists.txt -H./ -Bbuild/out_tizen_%{rpm} -DLIBDIR=%{_libdir} -DINCLUDEDIR=%{_includedir} -DTIZEN_MAJOR_VERSION='%{tizen_version_major}' \
-DESCARGOT_ARCH='%{tizen_arch}' -DESCARGOT_WASM='%{enable_wasm}' -DESCARGOT_DEBUGGER='%{enable_debugger}' -DESCARGOT_SMALL_CONFIG='%{enable_small_config}' \
-DESCARGOT_THREADING=ON -DESCARGOT_TLS_ACCESS_BY_ADDRESS=ON -DESCARGOT_MODE=release -DESCARGOT_HOST=tizen -DESCARGOT_OUTPUT=shared_lib -G Ninja
-DESCARGOT_ARCH='%{tizen_arch}' -DESCARGOT_WASM='%{enable_wasm}' -DESCARGOT_DEBUGGER='%{enable_debugger}' \
-DESCARGOT_THREADING=ON -DESCARGOT_MODE=release -DESCARGOT_HOST=tizen -DESCARGOT_OUTPUT=shared_lib -G Ninja
%endif
cmake --build build/out_tizen_%{rpm}
@ -281,7 +272,7 @@ cmake --build build/out_tizen_%{rpm}
CXXFLAGS+=' -DESCARGOT_ENABLE_TEST '
%endif
g++ src/shell/Shell.cpp -std=c++11 -Lbuild/out_tizen_%{rpm} -Isrc/ -Ithird_party/GCutil/include -o build/out_tizen_%{rpm}/escargot -O2 -DNDEBUG -Wl,-rpath=\$ORIGIN -Wl,-rpath=%{_libdir}/escargot ${CXXFLAGS} -lescargot -lpthread
g++ src/shell/Shell.cpp -std=c++11 -Lbuild/out_tizen_%{rpm} -Isrc/ -Ithird_party/GCutil -Ithird_party/GCutil/bdwgc/include -o build/out_tizen_%{rpm}/escargot -O2 -DNDEBUG -Wl,-rpath=\$ORIGIN ${CXXFLAGS} -lescargot -lpthread
g++ tools/test/test-data-runner/test-data-runner.cpp -o build/out_tizen_%{rpm}/test-data-runner -std=c++11 ${CXXFLAGS} -lpthread
%endif
@ -332,7 +323,6 @@ cp packaging/escargot.conf %{buildroot}%{_sysconfdir}/ld.so.conf.d/
%files profile_tv
%manifest packaging/%{name}.manifest
%{_libdir}/escargot/libescargot.so*
%{_sysconfdir}/ld.so.conf.d/*.conf
%license LICENSE.BSD-2-Clause LICENSE.LGPL-2.1+ LICENSE.MPL-2.0 LICENSE.Apache-2.0 LICENSE.BSD-3-Clause LICENSE.MIT LICENSE.BOEHM-GC
%endif
@ -340,7 +330,6 @@ cp packaging/escargot.conf %{buildroot}%{_sysconfdir}/ld.so.conf.d/
%files profile_headless
%manifest packaging/%{name}.manifest
%{_libdir}/escargot/libescargot.so*
%{_sysconfdir}/ld.so.conf.d/*.conf
%license LICENSE.BSD-2-Clause LICENSE.LGPL-2.1+ LICENSE.MPL-2.0 LICENSE.Apache-2.0 LICENSE.BSD-3-Clause LICENSE.MIT LICENSE.BOEHM-GC
%endif

View file

@ -264,16 +264,6 @@ if (f.type == Type::B) { puts("failed in msvc."); }
#define HAVE_BUILTIN_ATOMIC_FUNCTIONS
#endif
#if defined(COMPILER_CLANG)
#if __has_feature(address_sanitizer)
#define ASAN_ENABLED
#endif
#elif defined(COMPILER_GCC)
#if defined(__SANITIZE_ADDRESS__)
#define ASAN_ENABLED
#endif
#endif
#if defined(COMPILER_MSVC)
#include <stddef.h>
#endif
@ -295,15 +285,14 @@ extern "C" {
#ifdef ENABLE_ICU
#if defined(ENABLE_RUNTIME_ICU_BINDER)
typedef unsigned char LChar;
#include "RuntimeICUBinder.h"
#include "ICUPolyfill.h"
#else
#define U_SHOW_CPLUSPLUS_API 0
#define U_SHOW_CPLUSPLUS_HEADER_API 0
#if defined(OS_WINDOWS)
#include <icu.h>
#else
#include <unicode/utypes.h>
#include <unicode/locid.h>
#include <unicode/uchar.h>
#include <unicode/ustring.h>
@ -318,16 +307,13 @@ extern "C" {
#include <unicode/unum.h> // for Intl
#include <unicode/upluralrules.h> // for Intl
#include <unicode/unumberformatter.h> // for Intl
#include <unicode/unumberrangeformatter.h> // for Intl
#include <unicode/ureldatefmt.h> // for Intl
#include <unicode/uformattedvalue.h> // for Intl
#include <unicode/ucurr.h> // for Intl
#include <unicode/uloc.h> // for Intl
#include <unicode/uldnames.h> // for Intl
#include <unicode/ulistformatter.h> // for Intl
#include <unicode/ures.h> // for Intl
#include <unicode/udateintervalformat.h> // for Intl
#include <unicode/ubrk.h> // for Intl
// FIXME replace these vzone decl into include
// I declare vzone api because there is no header file in include folder
extern "C" {
@ -339,11 +325,6 @@ UBool vzone_getTZURL(VZone* zone, UChar*& url, int32_t& urlLength);
void vzone_getOffset3(VZone* zone, UDate date, UBool local, int32_t& rawOffset,
int32_t& dstOffset, UErrorCode& ec);
int32_t vzone_getRawOffset(VZone* zone);
// uresimp.h
U_CAPI UResourceBundle* U_EXPORT2
ures_findResource(const char* pathToResource,
UResourceBundle* fillIn, UErrorCode* status);
}
#endif // !defined(OS_WINDOWS_UWP)
@ -356,13 +337,11 @@ typedef unsigned char LChar;
typedef int32_t UChar32;
// macros from icu
#define U16_IS_LEAD(c) (((c) & 0xfffffc00) == 0xd800)
#define U16_IS_TRAIL(c) (((c) & 0xfffffc00) == 0xdc00)
#define U_IS_SURROGATE(c) (((c) & 0xfffff800) == 0xd800)
#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
#define U16_IS_LEAD(c) (((c)&0xfffffc00) == 0xd800)
#define U16_IS_TRAIL(c) (((c)&0xfffffc00) == 0xdc00)
#define U16_SURROGATE_OFFSET ((0xd800 << 10UL) + 0xdc00 - 0x10000)
#define U16_GET_SUPPLEMENTARY(lead, trail) \
(((UChar32)(lead) << 10UL) + (UChar32)(trail) - U16_SURROGATE_OFFSET)
(((UChar32)(lead) << 10UL) + (UChar32)(trail)-U16_SURROGATE_OFFSET)
#define U16_NEXT(s, i, length, c) \
{ \
@ -544,27 +523,19 @@ typedef uint16_t LexicalBlockIndex;
#define STACK_GROWS_DOWN
#endif
#ifndef STACK_FREESPACE_FROM_LIMIT
#define STACK_FREESPACE_FROM_LIMIT (1024 * 256) // 256KB
#endif
#ifndef STACK_USAGE_LIMIT
#ifdef ESCARGOT_ENABLE_TEST
#define STACK_USAGE_LIMIT (1024 * 1024 * 2) // 2MB
#else
#define STACK_USAGE_LIMIT (1024 * 1024 * 4) // 4MB
#endif
#ifndef STACK_LIMIT_FROM_BASE
#define STACK_LIMIT_FROM_BASE (1024 * 1024 * 3) // 3MB
#endif
#ifdef STACK_GROWS_DOWN
#define CHECK_STACK_OVERFLOW(state) \
if (UNLIKELY(ThreadLocal::stackLimit() > (size_t)currentStackPointer())) { \
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
#define CHECK_STACK_OVERFLOW(state) \
if (UNLIKELY(state.stackLimit() > (size_t)currentStackPointer())) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
}
#else
#define CHECK_STACK_OVERFLOW(state) \
if (UNLIKELY(ThreadLocal::stackLimit() < (size_t)currentStackPointer())) { \
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
#define CHECK_STACK_OVERFLOW(state) \
if (UNLIKELY(state.stackLimit() < (size_t)currentStackPointer())) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
}
#endif
@ -589,53 +560,29 @@ typedef uint16_t LexicalBlockIndex;
#define REGEXP_CACHE_SIZE_MAX 64
#endif
// maximum number of tail call arguments allowed
#ifndef TCO_ARGUMENT_COUNT_LIMIT
#define TCO_ARGUMENT_COUNT_LIMIT 8
#endif
// represent that a function could throw an exception
#define MAY_EXCEPTION
#include <tsl/robin_set.h>
template <class Key, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>,
bool StoreHash = false,
class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
using HashSet = tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
#include <tsl/robin_map.h>
namespace Escargot {
#if defined(ESCARGOT_SMALL_CONFIG)
template <class Key, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>,
bool StoreHash = false,
class GrowthPolicy = tsl::rh::mod_growth_policy<std::ratio<5, 4>>>
using HashSet = tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
template <class Key, class T, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key, T>>,
bool StoreHash = false,
class GrowthPolicy = tsl::rh::mod_growth_policy<std::ratio<5, 4>>>
using HashMap = tsl::robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
#else
template <class Key, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>,
bool StoreHash = false,
class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
using HashSet = tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
template <class Key, class T, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key, T>>,
bool StoreHash = false,
class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
using HashMap = tsl::robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
#endif
} // namespace Escargot
#include "EscargotInfo.h"
#include "heap/Heap.h"
#include "util/Util.h"
#include "util/Optional.h"
#include "util/Variant.h"
#include "runtime/ThreadLocal.h"
#endif

File diff suppressed because it is too large Load diff

View file

@ -84,14 +84,12 @@
F(RangeErrorObject) \
F(ReferenceErrorObject) \
F(SyntaxErrorObject) \
F(SuppressedErrorObject) \
F(TypeErrorObject) \
F(URIErrorObject)
#define ESCARGOT_TYPEDARRAY_REF_LIST(F) \
F(BigInt64ArrayObject) \
F(BigUint64ArrayObject) \
F(Float16ArrayObject) \
F(Float32ArrayObject) \
F(Float64ArrayObject) \
F(Int16ArrayObject) \
@ -154,42 +152,23 @@ public:
static void* gcMallocUncollectable(size_t siz); // allocate memory it can hold gc-allocated pointer & it is never collect by gc
static void* gcMallocAtomicUncollectable(size_t siz); // allocate memory it can not hold gc-allocated pointer & it is never collect by gc
static void gcFree(void* ptr);
typedef void (*GCAllocatedMemoryFinalizer)(void* self, void* callbackData);
typedef void (*GCAllocatedMemoryFinalizer)(void* self);
// gcRegisterFinalizer
// 1. if you want to free memory explicitly, you must remove registered finalizer
// if there was no finalizer, you can just free memory
// ex) void* gcPointer;
// Memory::gcRegisterFinalizer(gcPointer, callback...);
// gcRegisterFinalizer(gcPointer, ....);
// ......
// Memory::gcUnregisterFinalizer(gcPointer, callback...); // this removes finalizer
// gcRegisterFinalizer(gcPointer, nullptr); // this removes finalizer
// Memory::gcFree(gcPointer);
// 2. the data parameter will be considered accessible by gc.
static void gcRegisterFinalizer(void* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcUnregisterFinalizer(void* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static bool gcHasFinalizer(void* ptr);
static bool gcHasFinalizer(void* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcRegisterFinalizer(void* ptr, GCAllocatedMemoryFinalizer callback);
static void gcRegisterFinalizer(ValueRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcUnregisterFinalizer(ValueRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static bool gcHasFinalizer(ValueRef* ptr);
static bool gcHasFinalizer(ValueRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcRegisterFinalizer(ObjectRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcUnregisterFinalizer(ObjectRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static bool gcHasFinalizer(ObjectRef* ptr);
static bool gcHasFinalizer(ObjectRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcRegisterFinalizer(SymbolRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcUnregisterFinalizer(SymbolRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static bool gcHasFinalizer(SymbolRef* ptr);
static bool gcHasFinalizer(SymbolRef* ptr, GCAllocatedMemoryFinalizer callback, void* data);
static void gcRegisterFinalizer(ObjectRef* ptr, GCAllocatedMemoryFinalizer callback);
static void gcUnregisterFinalizer(ObjectRef* ptr, GCAllocatedMemoryFinalizer callback);
static void gc();
static void disableGC();
static void enableGC();
static size_t heapSize(); // Return the number of bytes in the heap. Excludes bdwgc private data structures. Excludes the unmapped memory
static size_t totalSize(); // Return the total number of bytes allocated in this process
@ -210,39 +189,9 @@ public:
static void setGCFrequency(size_t value = 1);
};
class ESCARGOT_EXPORT PersistentRefHolderBase {
public:
void setWeak();
void clearWeak();
bool isWeak();
protected:
PersistentRefHolderBase()
{
m_holder = nullptr;
}
template <typename T>
void initHolderSpace(T* initialValue)
{
m_holder = reinterpret_cast<void**>(Memory::gcMallocUncollectable(sizeof(T*)));
*(reinterpret_cast<T**>(m_holder)) = initialValue;
}
void destoryHolderSpace()
{
if (m_holder) {
Memory::gcFree(m_holder);
}
m_holder = nullptr;
}
void** m_holder;
};
// NOTE only {stack, kinds of PersistentHolders} are root set. if you store the data you need on other space, you may lost your data
template <typename T>
class ESCARGOT_EXPORT PersistentRefHolder : public PersistentRefHolderBase {
class ESCARGOT_EXPORT PersistentRefHolder {
public:
~PersistentRefHolder()
{
@ -251,6 +200,7 @@ public:
PersistentRefHolder()
{
m_holder = nullptr;
}
PersistentRefHolder(T* ptr)
@ -290,22 +240,18 @@ public:
operator T*()
{
return m_holder ? *(reinterpret_cast<T**>(m_holder)) : nullptr;
return *m_holder;
}
T* get()
{
if (m_holder) {
return *(reinterpret_cast<T**>(m_holder));
} else {
return nullptr;
}
return *m_holder;
}
T* release()
{
if (m_holder) {
T* ptr = *(reinterpret_cast<T**>(m_holder));
T* ptr = *m_holder;
destoryHolderSpace();
return ptr;
}
@ -314,8 +260,25 @@ public:
T* operator->()
{
return *(reinterpret_cast<T**>(m_holder));
return *m_holder;
}
private:
void initHolderSpace(T* initialValue)
{
m_holder = (T**)Memory::gcMallocUncollectable(sizeof(T*));
*m_holder = initialValue;
}
void destoryHolderSpace()
{
if (m_holder) {
Memory::gcFree(m_holder);
}
m_holder = nullptr;
}
T** m_holder;
};
class PersistentValueRefMap {
@ -618,40 +581,34 @@ public:
template <typename... Args, typename F>
static EvaluatorResult execute(ContextRef* ctx, F&& closure, Args... args)
{
typedef ValueRef* (*Closure)(ExecutionStateRef* state, Args...);
typedef ValueRef* (*Closure)(ExecutionStateRef * state, Args...);
return executeImpl(ctx, Closure(closure), args...);
}
template <typename... Args, typename F>
static EvaluatorResult execute(ExecutionStateRef* parent, F&& closure, Args... args)
{
typedef ValueRef* (*Closure)(ExecutionStateRef* state, Args...);
return executeImpl(parent, Closure(closure), args...);
}
static EvaluatorResult executeFunction(ContextRef* ctx, ValueRef* (*runner)(ExecutionStateRef* state, void* passedData), void* data);
static EvaluatorResult executeFunction(ContextRef* ctx, ValueRef* (*runner)(ExecutionStateRef* state, void* passedData, void* passedData2), void* data, void* data2);
static EvaluatorResult executeFunction(ExecutionStateRef* parent, ValueRef* (*runner)(ExecutionStateRef* state, void* passedData, void* passedData2), void* data, void* data2);
private:
template <typename P, typename... Args>
static EvaluatorResult executeImpl(P* p, ValueRef* (*fn)(ExecutionStateRef* state, Args...), Args... args)
template <typename... Args>
static EvaluatorResult executeImpl(ContextRef* ctx, ValueRef* (*fn)(ExecutionStateRef* state, Args...), Args... args)
{
typedef ValueRef* (*Closure)(ExecutionStateRef* state, Args...);
typedef ValueRef* (*Closure)(ExecutionStateRef * state, Args...);
std::tuple<ExecutionStateRef*, Args...> tuple = std::tuple<ExecutionStateRef*, Args...>(nullptr, args...);
return executeFunction(p, [](ExecutionStateRef* state, void* tuplePtr, void* fnPtr) -> ValueRef* {
return executeFunction(ctx, [](ExecutionStateRef* state, void* tuplePtr, void* fnPtr) -> ValueRef* {
std::tuple<ExecutionStateRef*, Args...>* tuple = (std::tuple<ExecutionStateRef*, Args...>*)tuplePtr;
Closure fn = (Closure)fnPtr;
std::get<0>(*tuple) = state;
return EvaluatorUtil::applyTupleIntoArgumentsOfVariadicTemplateFunction(fn, *tuple); }, &tuple, (void*)fn);
return EvaluatorUtil::applyTupleIntoArgumentsOfVariadicTemplateFunction(fn, *tuple);
},
&tuple, (void*)fn);
}
};
// temporally disable StackOverflow check
// StackOverflowDisabler only unlocks the predefined stack limit (STACK_USAGE_LIMIT: 4MB)
// StackOverflowDisabler only unlocks the predefined stack limit (STACK_LIMIT_FROM_BASE: 3MB)
// should be carefully used because it cannot prevent the system-stackoverflow exception
class ESCARGOT_EXPORT StackOverflowDisabler {
public:
@ -671,7 +628,6 @@ public:
GCManagedVector<FunctionObjectRef*> resolveCallstack(); // resolve list of callee
GlobalObjectRef* resolveCallerLexicalGlobalObject(); // resolve caller's lexical global object
// only enabled when `ENABLE_EXTENDED_API` macro is set (default: disabled)
bool onTry();
bool onCatch();
bool onFinally();
@ -679,6 +635,8 @@ public:
void throwException(ValueRef* value);
void checkStackOverflow();
bool hasPendingException();
GCManagedVector<Evaluator::StackTraceData> computeStackTrace();
ContextRef* context();
@ -697,8 +655,6 @@ public:
// register ErrorCallback which is triggered when each Error constructor (e.g. new TypeError()) invoked or thrown
// parameter `err` stands for the newly created ErrorObject
// these functions are used only for third party usage
// only enabled when `ENABLE_EXTENDED_API` macro is set (default: disabled)
typedef void (*ErrorCallback)(ExecutionStateRef* state, ErrorObjectRef* err);
void registerErrorCreationCallback(ErrorCallback cb);
void registerErrorThrowCallback(ErrorCallback cb);
@ -729,21 +685,10 @@ public:
void registerPromiseRejectCallback(PromiseRejectCallback);
void unregisterPromiseRejectCallback();
enum class ConfigFlag {
CompressCompressibleStringsWhileGC = 1,
PruneCompiledByteCodesWhileGC = 1 << 1,
CompressCompressibleStringsEnterIdle = 1 << 3,
PruneCompiledByteCodesEnterIdle = 1 << 4,
UnloadReloadableStringsEnterIdle = 1 << 5,
};
size_t config();
void setConfig(size_t s);
// this function enforce do gc,
// remove every compiled bytecodes(if enabled),
// remove every compiled bytecodes,
// remove regexp cache,
// and compress every comressible strings(if enabled) if we can
// and compress every comressible strings if we can
void enterIdleMode();
// force clear every caches related with context
// you can call this function if you don't want to use every alive contexts
@ -762,28 +707,13 @@ public:
SymbolRef* replaceSymbol();
SymbolRef* splitSymbol();
SymbolRef* asyncIteratorSymbol();
SymbolRef* disposeSymbol();
SymbolRef* asyncDisposeSymbol();
bool hasPendingJob();
Evaluator::EvaluatorResult executePendingJob();
typedef ValueRef* (*EvaluateJobCallback)(ExecutionStateRef* state, void* data);
void enqueueEvaluateJob(ContextRef* relatedContext, EvaluateJobCallback callback, void* data);
bool hasPendingJobFromAnotherThread();
bool waitEventFromAnotherThread(unsigned timeoutInMillisecond = 0); // zero means infinity
void executePendingJobFromAnotherThread();
size_t maxCompiledByteCodeSize();
void setMaxCompiledByteCodeSize(size_t s);
bool isCodeCacheEnabled();
size_t codeCacheMinSourceLength();
void setCodeCacheMinSourceLength(size_t s);
size_t codeCacheMaxCacheCount();
void setCodeCacheMaxCacheCount(size_t s);
bool codeCacheShouldLoadFunctionOnScriptLoading();
void setCodeCacheShouldLoadFunctionOnScriptLoading(bool s);
};
class ESCARGOT_EXPORT DebuggerOperationsRef {
@ -920,7 +850,6 @@ public:
// Base class for debugger callbacks
class DebuggerClient {
public:
virtual ~DebuggerClient() {};
virtual void parseCompleted(StringRef* source, StringRef* srcName, std::vector<DebuggerOperationsRef::BreakpointLocationsInfo*>& breakpointLocationsVector) = 0;
virtual void parseError(StringRef* source, StringRef* srcName, StringRef* error) = 0;
virtual void codeReleased(WeakCodeRef* weakCodeRef) = 0;
@ -947,21 +876,17 @@ public:
// this setter try to update `globalThis` value on GlobalObject
void setGlobalObjectProxy(ObjectRef* newGlobalObjectProxy);
bool canThrowException();
void throwException(ValueRef* exceptionValue);
void throwException(ValueRef* exceptionValue); // if you use this function without Evaluator, your program will crash :(
bool initDebuggerClient(DebuggerOperationsRef::DebuggerClient* debuggerClient);
bool disableDebugger();
bool initDebugger(DebuggerOperationsRef::DebuggerClient* debuggerClient);
// available options(separator is ';')
// "--port=6501", default for TCP debugger
bool initDebugger(const char* options);
bool initDebuggerRemote(const char* options);
bool isDebuggerRunning();
bool isWaitBeforeExit();
bool isDebuggerRestartTrue();
void printDebugger(StringRef* output);
void pumpDebuggerEvents();
void setAsAlwaysStopState();
void setDebuggerRestart();
StringRef* getClientSource(StringRef** sourceName);
typedef OptionalRef<ValueRef> (*VirtualIdentifierCallback)(ExecutionStateRef* state, ValueRef* name);
@ -1016,12 +941,14 @@ public:
}
static ValueRef* createNull();
static ValueRef* createUndefined();
static ValueRef* createException();
bool isStoredInHeap();
bool isBoolean();
bool isNumber();
bool isNull();
bool isUndefined();
bool isException();
bool isInt32();
bool isUInt32();
bool isDouble();
@ -1088,8 +1015,6 @@ public:
bool instanceOf(ExecutionStateRef* state, const ValueRef* other) const;
ValueRef* call(ExecutionStateRef* state, ValueRef* receiver, const size_t argc, ValueRef** argv);
ValueRef* construct(ExecutionStateRef* state, const size_t argc, ValueRef** argv); // same with new expression in js
// call constrictor with already created object
void callConstructor(ExecutionStateRef* state, ObjectRef* receiver, const size_t argc, ValueRef** argv);
};
class ESCARGOT_EXPORT ValueVectorRef {
@ -1220,8 +1145,7 @@ class ESCARGOT_EXPORT SymbolRef : public PointerValueRef {
public:
static SymbolRef* create(OptionalRef<StringRef> desc);
static SymbolRef* fromGlobalSymbolRegistry(VMInstanceRef* context, StringRef* desc); // this is same with Symbol.for
StringRef* descriptionString();
ValueRef* descriptionValue();
OptionalRef<StringRef> description();
StringRef* symbolDescriptiveString();
};
@ -1457,7 +1381,6 @@ public:
ValueRef* getPrototype(ExecutionStateRef* state);
OptionalRef<ObjectRef> getPrototypeObject(ExecutionStateRef* state); // if __proto__ is not object(undefined or null), this function returns nullptr instead of orginal value.
bool setPrototype(ExecutionStateRef* state, ValueRef* value);
bool setObjectPrototype(ExecutionStateRef* state, ValueRef* value); // explicitly call Object::setPrototype
StringRef* constructorName(ExecutionStateRef* state);
@ -1470,11 +1393,6 @@ public:
// get `length` property like ToLength(Get(obj, "length"))
// it returns 0 for exceptional cases (e.g. undefined, nan)
uint64_t length(ExecutionStateRef* state);
void setLength(ExecutionStateRef* state, uint64_t newLength);
IteratorObjectRef* values(ExecutionStateRef* state);
IteratorObjectRef* keys(ExecutionStateRef* state);
IteratorObjectRef* entries(ExecutionStateRef* state);
bool isExtensible(ExecutionStateRef* state);
bool preventExtensions(ExecutionStateRef* state);
@ -1482,13 +1400,12 @@ public:
void* extraData();
void setExtraData(void* e);
// this function is used only for test purpose
#if defined(ESCARGOT_ENABLE_TEST)
void setIsHTMLDDA();
#endif
void removeFromHiddenClassChain();
void preparePropertyStorageForPropertyAddition(size_t expandCount);
// DEPRECATED! this function will be removed
void removeFromHiddenClassChain(ExecutionStateRef* state);
};
@ -1516,8 +1433,6 @@ public:
ObjectRef* evalErrorPrototype();
FunctionObjectRef* aggregateError();
ObjectRef* aggregateErrorPrototype();
FunctionObjectRef* suppressedError();
ObjectRef* suppressedErrorPrototype();
FunctionObjectRef* string();
ObjectRef* stringPrototype();
FunctionObjectRef* number();
@ -1536,12 +1451,6 @@ public:
FunctionObjectRef* jsonParse();
FunctionObjectRef* promise();
FunctionObjectRef* promiseAll();
FunctionObjectRef* promiseAllSettled();
FunctionObjectRef* promiseAny();
FunctionObjectRef* promiseRace();
FunctionObjectRef* promiseReject();
FunctionObjectRef* promiseResolve();
ObjectRef* promisePrototype();
FunctionObjectRef* arrayBuffer();
@ -1562,8 +1471,6 @@ public:
ObjectRef* uint32ArrayPrototype();
ObjectRef* uint8ClampedArray();
ObjectRef* uint8ClampedArrayPrototype();
ObjectRef* float16Array();
ObjectRef* float16ArrayPrototype();
ObjectRef* float32Array();
ObjectRef* float32ArrayPrototype();
ObjectRef* float64Array();
@ -1641,9 +1548,6 @@ public:
static FunctionObjectRef* create(ExecutionStateRef* state, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body);
static FunctionObjectRef* create(ExecutionStateRef* state, StringRef* sourceName, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body);
// returns associate context
ContextRef* context();
// get prototype property of constructible function(not [[prototype]])
// this property is used for new object construction. see https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarycreatefromconstructor
ValueRef* getFunctionPrototype(ExecutionStateRef* state);
@ -1677,6 +1581,9 @@ public:
static ArrayObjectRef* create(ExecutionStateRef* state);
static ArrayObjectRef* create(ExecutionStateRef* state, const uint64_t size);
static ArrayObjectRef* create(ExecutionStateRef* state, ValueVectorRef* source);
IteratorObjectRef* values(ExecutionStateRef* state);
IteratorObjectRef* keys(ExecutionStateRef* state);
IteratorObjectRef* entries(ExecutionStateRef* state);
};
class ESCARGOT_EXPORT ErrorObjectRef : public ObjectRef {
@ -1690,10 +1597,8 @@ public:
URIError,
EvalError,
AggregateError,
SuppressedError,
};
static ErrorObjectRef* create(ExecutionStateRef* state, ErrorObjectRef::Code code, StringRef* errorMessage);
void updateStackTraceData(ExecutionStateRef* state); // update stacktrace data
};
class ESCARGOT_EXPORT ReferenceErrorObjectRef : public ErrorObjectRef {
@ -1731,11 +1636,6 @@ public:
static AggregateErrorObjectRef* create(ExecutionStateRef* state, StringRef* errorMessage);
};
class ESCARGOT_EXPORT SuppressedErrorObjectRef : public ErrorObjectRef {
public:
static SuppressedErrorObjectRef* create(ExecutionStateRef* state, StringRef* errorMessage, ValueRef* error, ValueRef* suppressed);
};
class ESCARGOT_EXPORT DateObjectRef : public ObjectRef {
public:
static DateObjectRef* create(ExecutionStateRef* state);
@ -1790,14 +1690,12 @@ class ESCARGOT_EXPORT RegExpObjectRef : public ObjectRef {
public:
enum RegExpObjectOption {
None = 0 << 0,
HasIndices = 1 << 0,
Global = 1 << 1,
IgnoreCase = 1 << 2,
MultiLine = 1 << 3,
DotAll = 1 << 4,
Unicode = 1 << 5,
UnicodeSets = 1 << 6,
Sticky = 1 << 7,
Global = 1 << 0,
IgnoreCase = 1 << 1,
MultiLine = 1 << 2,
Sticky = 1 << 3,
Unicode = 1 << 4,
DotAll = 1 << 5,
};
struct ESCARGOT_EXPORT RegexMatchResult {
@ -1916,11 +1814,6 @@ public:
static Uint8ClampedArrayObjectRef* create(ExecutionStateRef* state);
};
class ESCARGOT_EXPORT Float16ArrayObjectRef : public ArrayBufferViewRef {
public:
static Float16ArrayObjectRef* create(ExecutionStateRef* state);
};
class ESCARGOT_EXPORT Float32ArrayObjectRef : public ArrayBufferViewRef {
public:
static Float32ArrayObjectRef* create(ExecutionStateRef* state);
@ -1954,9 +1847,8 @@ public:
ValueRef* promiseResult();
ObjectRef* then(ExecutionStateRef* state, ValueRef* handler);
ObjectRef* then(ExecutionStateRef* state, ValueRef* onFulfilled, ValueRef* onRejected);
ObjectRef* catchOperation(ExecutionStateRef* state, ValueRef* handler);
ObjectRef* then(ExecutionStateRef* state, ValueRef* onFulfilled, ValueRef* onRejected);
void fulfill(ExecutionStateRef* state, ValueRef* value);
void reject(ExecutionStateRef* state, ValueRef* reason);
@ -1981,14 +1873,17 @@ public:
bool deleteOperation(ExecutionStateRef* state, ValueRef* key);
bool has(ExecutionStateRef* state, ValueRef* key);
size_t size(ExecutionStateRef* state);
IteratorObjectRef* values(ExecutionStateRef* state);
IteratorObjectRef* keys(ExecutionStateRef* state);
IteratorObjectRef* entries(ExecutionStateRef* state);
};
class ESCARGOT_EXPORT WeakSetObjectRef : public ObjectRef {
public:
static WeakSetObjectRef* create(ExecutionStateRef* state);
bool add(ExecutionStateRef* state, ValueRef* key);
bool deleteOperation(ExecutionStateRef* state, ValueRef* key);
bool has(ExecutionStateRef* state, ValueRef* key);
void add(ExecutionStateRef* state, ObjectRef* key);
bool deleteOperation(ExecutionStateRef* state, ObjectRef* key);
bool has(ExecutionStateRef* state, ObjectRef* key);
};
class ESCARGOT_EXPORT MapObjectRef : public ObjectRef {
@ -2000,23 +1895,26 @@ public:
bool has(ExecutionStateRef* state, ValueRef* key);
void set(ExecutionStateRef* state, ValueRef* key, ValueRef* value);
size_t size(ExecutionStateRef* state);
IteratorObjectRef* values(ExecutionStateRef* state);
IteratorObjectRef* keys(ExecutionStateRef* state);
IteratorObjectRef* entries(ExecutionStateRef* state);
};
class ESCARGOT_EXPORT WeakMapObjectRef : public ObjectRef {
public:
static WeakMapObjectRef* create(ExecutionStateRef* state);
bool deleteOperation(ExecutionStateRef* state, ValueRef* key);
ValueRef* get(ExecutionStateRef* state, ValueRef* key);
bool has(ExecutionStateRef* state, ValueRef* key);
void set(ExecutionStateRef* state, ValueRef* key, ValueRef* value);
bool deleteOperation(ExecutionStateRef* state, ObjectRef* key);
ValueRef* get(ExecutionStateRef* state, ObjectRef* key);
bool has(ExecutionStateRef* state, ObjectRef* key);
void set(ExecutionStateRef* state, ObjectRef* key, ValueRef* value);
};
class ESCARGOT_EXPORT WeakRefObjectRef : public ObjectRef {
public:
static OptionalRef<WeakRefObjectRef> create(ExecutionStateRef* state, ValueRef* target);
static WeakRefObjectRef* create(ExecutionStateRef* state, ObjectRef* target);
// returns true if target is alive
bool deleteOperation(ExecutionStateRef* state);
OptionalRef<PointerValueRef> deref();
OptionalRef<ObjectRef> deref();
};
class ESCARGOT_EXPORT FinalizationRegistryObjectRef : public ObjectRef {
@ -2028,7 +1926,6 @@ public:
// it is not intented operation
// Note) only String or Symbol type is allowed for `propertyName`
// because TemplateRef is set without ExecutionStateRef, so property name conversion is impossible.
// only enabled when `ENABLE_EXTENDED_API` macro is set (default: disabled)
class ESCARGOT_EXPORT TemplateRef {
public:
void set(ValueRef* propertyName, ValueRef* data, bool isWritable, bool isEnumerable, bool isConfigurable);
@ -2112,7 +2009,13 @@ struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerConfiguration {
}
};
// only enabled when `ENABLE_EXTENDED_API` macro is set (default: disabled)
class ESCARGOT_EXPORT SerializerRef {
public:
// returns the serialization was successful
static bool serializeInto(ValueRef* value, std::ostringstream& output);
static ValueRef* deserializeFrom(ContextRef* context, std::istringstream& input);
};
class ESCARGOT_EXPORT ObjectTemplateRef : public TemplateRef {
public:
static ObjectTemplateRef* create();
@ -2129,7 +2032,6 @@ public:
};
// FunctionTemplateRef returns the unique function instance in context.
// only enabled when `ENABLE_EXTENDED_API` macro is set (default: disabled)
class ESCARGOT_EXPORT FunctionTemplateRef : public TemplateRef {
public:
// in constructor call, thisValue is default consturcted object
@ -2152,13 +2054,6 @@ public:
OptionalRef<FunctionTemplateRef> parent();
};
class ESCARGOT_EXPORT SerializerRef {
public:
// returns the serialization was successful
static bool serializeInto(ValueRef* value, std::ostringstream& output);
static ValueRef* deserializeFrom(ContextRef* context, std::istringstream& input);
};
class ESCARGOT_EXPORT ScriptParserRef {
public:
struct ESCARGOT_EXPORT InitializeScriptResult {
@ -2237,7 +2132,7 @@ public:
{
return calloc(sizeInByte, 1);
}
virtual void onFreeArrayBufferObjectDataBuffer(void* buffer, size_t sizeInByte, void* deleterData)
virtual void onFreeArrayBufferObjectDataBuffer(void* buffer, size_t sizeInByte)
{
return free(buffer);
}
@ -2325,6 +2220,7 @@ public:
static ValueRef* copyStableBufferBytes(ExecutionStateRef* state, ValueRef* source);
static ObjectRef* asyncCompileModule(ExecutionStateRef* state, ValueRef* source);
static ObjectRef* instantiatePromiseOfModuleWithImportObject(ExecutionStateRef* state, PromiseObjectRef* promiseOfModule, ValueRef* importObj);
static void collectHeap();
};
} // namespace Escargot

File diff suppressed because it is too large Load diff

View file

@ -30,14 +30,13 @@ namespace Escargot {
static Value builtinArrayBufferConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
}
uint64_t byteLength = argv[0].toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(byteLength == Value::InvalidIndexValue)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
Optional<uint64_t> maxByteLength;
@ -45,15 +44,19 @@ static Value builtinArrayBufferConstructor(ExecutionState& state, Value thisValu
if (UNLIKELY((argc > 1) && argv[1].isObject())) {
Object* options = argv[1].asObject();
Value maxLengthValue = options->get(state, ObjectPropertyName(state.context()->staticStrings().maxByteLength)).value(state, options);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!maxLengthValue.isUndefined()) {
maxByteLength = maxLengthValue.toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY((maxByteLength.value() == Value::InvalidIndexValue) || (byteLength > maxByteLength.value()))) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
}
}
return ArrayBufferObject::allocateArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
ArrayBufferObject* result = ArrayBufferObject::allocateArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
RETURN_VALUE_IF_PENDING_EXCEPTION
return result;
}
// https://www.ecma-international.org/ecma-262/10.0/#sec-arraybuffer.isview
@ -72,11 +75,11 @@ static Value builtinArrayBufferIsView(ExecutionState& state, Value thisValue, si
}
#define RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isArrayBuffer() || thisValue.asObject()->isSharedArrayBufferObject())) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
\
#define RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isArrayBuffer() || thisValue.asObject()->isSharedArrayBufferObject())) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
\
ArrayBuffer* NAME = thisValue.asObject()->asArrayBuffer();
// https://262.ecma-international.org/#sec-get-arraybuffer.prototype.bytelength
@ -113,24 +116,19 @@ static Value builtinArrayBufferResizableGetter(ExecutionState& state, Value this
return Value(obj->isResizableArrayBuffer());
}
static Value builtinArrayBufferDetachedGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, getDetached);
return Value(obj->isDetachedBuffer());
}
static Value builtinArrayBufferResize(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, resize);
obj->throwTypeErrorIfDetached(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!obj->isResizableArrayBuffer()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
}
double newByteLength = argv[0].toInteger(state);
obj->throwTypeErrorIfDetached(state);
if (newByteLength < 0 || newByteLength > obj->maxByteLength()) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
obj->backingStore()->resize(static_cast<size_t>(newByteLength));
@ -142,54 +140,20 @@ static Value builtinArrayBufferTransfer(ExecutionState& state, Value thisValue,
{
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, transfer);
obj->throwTypeErrorIfDetached(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
uint64_t newByteLength = obj->byteLength();
double newByteLength = obj->byteLength();
if (argc > 0 && !argv[0].isUndefined()) {
newByteLength = argv[0].toIndex(state);
if (UNLIKELY(newByteLength == Value::InvalidIndexValue)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().transfer.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
newByteLength = argv[0].toInteger(state);
}
obj->throwTypeErrorIfDetached(state);
Optional<uint64_t> maxLength;
if (obj->isResizableArrayBuffer()) {
maxLength = obj->maxByteLength();
if (newByteLength > maxLength.value()) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().transfer.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
} else {
// For non-resizable ArrayBuffer, the new buffer should also be non-resizable
maxLength = newByteLength;
}
ArrayBuffer* newValue = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), newByteLength, maxLength, obj->isResizableArrayBuffer());
Value arguments[] = { Value(Value::DoubleToIntConvertibleTestNeeds, newByteLength) };
ArrayBuffer* newValue = Object::construct(state, state.context()->globalObject()->arrayBuffer(), 1, arguments).asObject()->asArrayBuffer();
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
// Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
newValue->fillData(obj->data(), std::min(newByteLength, static_cast<uint64_t>(obj->byteLength())));
obj->asArrayBufferObject()->detachArrayBuffer();
return newValue;
}
static Value builtinArrayBufferTransferToFixedLength(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, transferToFixedLength);
obj->throwTypeErrorIfDetached(state);
uint64_t newByteLength = obj->byteLength();
if (argc > 0 && !argv[0].isUndefined()) {
newByteLength = argv[0].toIndex(state);
if (UNLIKELY(newByteLength == Value::InvalidIndexValue)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().transferToFixedLength.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
}
}
ArrayBuffer* newValue = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), newByteLength, newByteLength, false);
// Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
// Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
newValue->fillData(obj->data(), std::min(newByteLength, static_cast<uint64_t>(obj->byteLength())));
newValue->fillData(obj->data(), std::min(newByteLength, static_cast<double>(obj->byteLength())));
obj->asArrayBufferObject()->detachArrayBuffer();
@ -202,6 +166,7 @@ static Value builtinArrayBufferSlice(ExecutionState& state, Value thisValue, siz
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, slice);
obj->throwTypeErrorIfDetached(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
double len = obj->byteLength();
double relativeStart = argv[0].toInteger(state);
@ -211,23 +176,29 @@ static Value builtinArrayBufferSlice(ExecutionState& state, Value thisValue, siz
size_t newLen = std::max((int)final_ - (int)first, 0);
Value constructor = obj->speciesConstructor(state, state.context()->globalObject()->arrayBuffer());
RETURN_VALUE_IF_PENDING_EXCEPTION
Value arguments[] = { Value(newLen) };
Object* newValue = Object::construct(state, constructor, 1, arguments).toObject(state);
Value res = Object::construct(state, constructor, 1, arguments);
RETURN_VALUE_IF_PENDING_EXCEPTION
Object* newValue = res.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!newValue->isArrayBuffer()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
}
ArrayBuffer* newObject = newValue->asArrayBuffer();
newObject->throwTypeErrorIfDetached(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (newObject == obj) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
}
if (newObject->byteLength() < newLen) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
}
obj->throwTypeErrorIfDetached(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
newObject->fillData(obj->data() + first, newLen);
return newObject;
@ -235,9 +206,12 @@ static Value builtinArrayBufferSlice(ExecutionState& state, Value thisValue, siz
void GlobalObject::initializeArrayBuffer(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->arrayBuffer(); }, nullptr);
return self->asGlobalObject()->arrayBuffer();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().ArrayBuffer), nativeData, Value(Value::EmptyValue));
}
@ -283,12 +257,6 @@ void GlobalObject::installArrayBuffer(ExecutionState& state)
Value(Value::EmptyValue));
ObjectPropertyDescriptor resizableDesc(resizableGS, ObjectPropertyDescriptor::ConfigurablePresent);
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->resizable), resizableDesc);
JSGetterSetter detachedGS(
new NativeFunctionObject(state, NativeFunctionInfo(strings->getDetached, builtinArrayBufferDetachedGetter, 0, NativeFunctionInfo::Strict)),
Value(Value::EmptyValue));
ObjectPropertyDescriptor detachedDesc(detachedGS, ObjectPropertyDescriptor::ConfigurablePresent);
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->detached), detachedDesc);
}
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->resize),
@ -297,9 +265,6 @@ void GlobalObject::installArrayBuffer(ExecutionState& state)
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->transfer),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->transfer, builtinArrayBufferTransfer, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->transferToFixedLength),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->transferToFixedLength, builtinArrayBufferTransferToFixedLength, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayBufferPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->slice),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->slice, builtinArrayBufferSlice, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -59,34 +59,33 @@ static Value asyncFromSyncIteratorValueUnwrap(ExecutionState& state, Value thisV
static Value asyncFromSyncIteratorContinuation(ExecutionState& state, Object* result, PromiseReaction::Capability promiseCapability)
{
// Let done be IteratorComplete(result).
bool done;
try {
done = IteratorObject::iteratorComplete(state, result);
} catch (const Value& thrownValue) {
bool done = IteratorObject::iteratorComplete(state, result);
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(done, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
// Let value be IteratorValue(result).
Value value;
try {
value = IteratorObject::iteratorValue(state, result);
} catch (const Value& thrownValue) {
Value value = IteratorObject::iteratorValue(state, result);
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(value, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
// Let valueWrapper be ? PromiseResolve(%Promise%, « value »).
PromiseObject* valueWrapper = nullptr;
try {
valueWrapper = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), value)->asPromiseObject();
} catch (const Value& thrownValue) {
PromiseObject* valueWrapper = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), value)->asPromiseObject();
if (UNLIKELY(state.hasPendingException())) {
// * added step from 2020 (esid: language/statements/for-await-of/async-from-sync-iterator-continuation-abrupt-completion-get-constructor.js)
// IfAbruptRejectPromise(valueWrapper, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
@ -107,31 +106,36 @@ static Value builtinAsyncFromSyncIteratorNext(ExecutionState& state, Value thisV
Value& O = thisValue;
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
ASSERT(!state.hasPendingException());
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
// Let invalidIteratorError be a newly created TypeError object.
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
// Let syncIteratorRecord be O.[[SyncIteratorRecord]].
auto syncIteratorRecord = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord();
Object* result;
try {
// Let result be IteratorNext(syncIteratorRecord, value).
// If value is present, then
// a. Let result be IteratorNext(syncIteratorRecord, value).
// Else,
// a. Let result be IteratorNext(syncIteratorRecord).
result = IteratorObject::iteratorNext(state, syncIteratorRecord, argc ? argv[0] : Value(Value::EmptyValue));
} catch (const Value& thrownValue) {
// Let result be IteratorNext(syncIteratorRecord, value).
// If value is present, then
// a. Let result be IteratorNext(syncIteratorRecord, value).
// Else,
// a. Let result be IteratorNext(syncIteratorRecord).
result = IteratorObject::iteratorNext(state, syncIteratorRecord, argc ? argv[0] : Value(Value::EmptyValue));
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(result, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
// Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
return asyncFromSyncIteratorContinuation(state, result, promiseCapability);
}
@ -144,25 +148,26 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
Value& O = thisValue;
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
ASSERT(!state.hasPendingException());
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
// Let invalidIteratorError be a newly created TypeError object.
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
// Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
Object* syncIterator = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord()->m_iterator;
// Let return be GetMethod(syncIterator, "return").
Value returnVariable;
try {
returnVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringReturn);
} catch (const Value& thrownValue) {
Value returnVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringReturn);
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(return, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
@ -172,25 +177,26 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
Value iterResult = IteratorObject::createIterResultObject(state, value, true);
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &iterResult);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
Value result;
try {
// If value is present, then
// a. Let result be Call(return, syncIterator, « value »).
// Else,
// a. Let result be Call(return, syncIterator).
if (argc) {
result = Object::call(state, returnVariable, syncIterator, 1, &value);
} else {
result = Object::call(state, returnVariable, syncIterator, 0, nullptr);
}
} catch (const Value& thrownValue) {
// If value is present, then
// a. Let result be Call(return, syncIterator, « value »).
// Else,
// a. Let result be Call(return, syncIterator).
if (argc) {
result = Object::call(state, returnVariable, syncIterator, 1, &value);
} else {
result = Object::call(state, returnVariable, syncIterator, 0, nullptr);
}
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(return, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
@ -199,6 +205,7 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
// Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
Value typeError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("result of iterator is not Object"));
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &typeError);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
@ -214,12 +221,14 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
Value& O = thisValue;
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
ASSERT(!state.hasPendingException());
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
// Let invalidIteratorError be a newly created TypeError object.
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
@ -227,13 +236,12 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
// Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
Object* syncIterator = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord()->m_iterator;
// Let throw be GetMethod(syncIterator, "throw").
Value throwVariable;
try {
throwVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringThrow);
} catch (const Value& thrownValue) {
Value throwVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringThrow);
if (state.hasPendingException()) {
// IfAbruptRejectPromise(return, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
@ -241,18 +249,18 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
if (throwVariable.isUndefined()) {
// Perform ! Call(promiseCapability.[[Reject]], undefined, « value »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &value);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
// Let result be Call(throw, syncIterator, « value »).
Value result;
try {
result = Object::call(state, throwVariable, syncIterator, 1, &value);
} catch (const Value& thrownValue) {
Value result = Object::call(state, throwVariable, syncIterator, 1, &value);
if (UNLIKELY(state.hasPendingException())) {
// IfAbruptRejectPromise(result, promiseCapability).
Value argv = thrownValue;
Value argv = state.detachPendingException();
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
@ -261,6 +269,7 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
// Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
Value typeError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("result of iterator is not Object"));
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &typeError);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}

View file

@ -30,8 +30,9 @@ namespace Escargot {
static Value builtinAsyncFunction(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString());
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, true, false);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
if (!newTarget.hasValue()) {
@ -40,6 +41,7 @@ static Value builtinAsyncFunction(ExecutionState& state, Value thisValue, size_t
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->asyncFunctionPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
return new ScriptAsyncFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
}

View file

@ -30,8 +30,9 @@ namespace Escargot {
static Value builtinAsyncGeneratorFunction(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString());
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, true, false);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
if (!newTarget.hasValue()) {
@ -40,6 +41,7 @@ static Value builtinAsyncGeneratorFunction(ExecutionState& state, Value thisValu
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->asyncGenerator();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
return new ScriptAsyncGeneratorFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
}
@ -100,7 +102,7 @@ void GlobalObject::installAsyncGenerator(ExecutionState& state)
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().stringThrow, builtinAsyncGeneratorThrow, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_asyncGeneratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(state.context()->staticStrings().AsyncGenerator.string(), ObjectPropertyDescriptor::ConfigurablePresent));
ObjectPropertyDescriptor(Value(state.context()->staticStrings().AsyncGenerator.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}
} // namespace Escargot

View file

@ -28,8 +28,6 @@
#include "runtime/Platform.h"
#include "runtime/PromiseObject.h"
#include "util/Yield.h"
namespace Escargot {
#if defined(ENABLE_THREADING)
@ -50,14 +48,15 @@ enum class AtomicBinaryOps : uint8_t {
static ArrayBuffer* validateIntegerTypedArray(ExecutionState& state, Value typedArray, bool waitable = false)
{
ArrayBuffer* buffer = TypedArrayObject::validateTypedArray(state, typedArray);
RETURN_NULL_IF_PENDING_EXCEPTION
TypedArrayObject* TA = typedArray.asObject()->asTypedArrayObject();
if (waitable) {
if ((TA->typedArrayType() != TypedArrayType::Int32) && (TA->typedArrayType() != TypedArrayType::BigInt64)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
} else if ((TA->typedArrayType() == TypedArrayType::Uint8Clamped) || (TA->typedArrayType() == TypedArrayType::Float16) || (TA->typedArrayType() == TypedArrayType::Float32) || (TA->typedArrayType() == TypedArrayType::Float64)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
} else if ((TA->typedArrayType() == TypedArrayType::Uint8Clamped) || (TA->typedArrayType() == TypedArrayType::Float32) || (TA->typedArrayType() == TypedArrayType::Float64)) {
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
return buffer;
@ -65,10 +64,10 @@ static ArrayBuffer* validateIntegerTypedArray(ExecutionState& state, Value typed
static size_t validateAtomicAccess(ExecutionState& state, TypedArrayObject* typedArray, Value index)
{
size_t length = typedArray->arrayLength();
uint64_t accessIndex = index.toIndex(state);
size_t length = typedArray->arrayLength();
if (UNLIKELY(accessIndex == Value::InvalidIndexValue || accessIndex >= (uint64_t)length)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
}
ASSERT(accessIndex < std::numeric_limits<size_t>::max());
@ -168,6 +167,7 @@ static Value getModifySetValueInBuffer(ExecutionState& state, ArrayBuffer* buffe
static Value atomicReadModifyWrite(ExecutionState& state, Value typedArray, Value index, Value value, AtomicBinaryOps op)
{
ArrayBuffer* buffer = validateIntegerTypedArray(state, typedArray);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* TA = typedArray.asObject()->asTypedArrayObject();
size_t indexedPosition = validateAtomicAccess(state, TA, index);
TypedArrayType type = TA->typedArrayType();
@ -175,6 +175,7 @@ static Value atomicReadModifyWrite(ExecutionState& state, Value typedArray, Valu
Value v;
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
v = value.toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
} else {
v = Value(Value::DoubleToIntConvertibleTestNeeds, value.toInteger(state));
}
@ -204,15 +205,19 @@ void atomicCompareExchange(uint8_t* rawStart, uint8_t* expectedBytes, uint8_t* r
static Value builtinAtomicsCompareExchange(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayType type = TA->typedArrayType();
Value expected;
Value replacement;
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
expected = argv[2].toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
replacement = argv[3].toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
} else {
expected = Value(Value::DoubleToIntConvertibleTestNeeds, argv[2].toInteger(state));
replacement = Value(Value::DoubleToIntConvertibleTestNeeds, argv[3].toInteger(state));
@ -285,8 +290,10 @@ static Value builtinAtomicsExchange(ExecutionState& state, Value thisValue, size
static Value builtinAtomicsLoad(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayType type = TA->typedArrayType();
return buffer->getValueFromBuffer(state, indexedPosition, type);
@ -300,14 +307,17 @@ static Value builtinAtomicsOr(ExecutionState& state, Value thisValue, size_t arg
static Value builtinAtomicsStore(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayType type = TA->typedArrayType();
Value value = argv[2];
Value v;
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
v = value.toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
} else {
v = Value(Value::DoubleToIntConvertibleTestNeeds, value.toInteger(state));
}
@ -331,19 +341,22 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
// https://tc39.es/proposal-atomics-wait-async/#sec-dowait
// Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
ArrayBuffer* buffer = validateIntegerTypedArray(state, typedArrayValue, true);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* typedArray = typedArrayValue.asObject()->asTypedArrayObject();
if (!buffer->isSharedArrayBufferObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "This function expects SharedArrayBuffer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "This function expects SharedArrayBuffer");
}
// Let i be ? ValidateAtomicAccess(typedArray, index).
size_t i = validateAtomicAccess(state, typedArray, index);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let arrayTypeName be typedArray.[[TypedArrayName]].
auto arrayTypeName = typedArray->typedArrayType();
// If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
Value v;
if (arrayTypeName == TypedArrayType::BigInt64) {
v = value.toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
} else {
// Otherwise, let v be ? ToInt32(value).
v = Value(value.toInt32(state));
@ -365,7 +378,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
// Let B be AgentCanSuspend().
// If B is false, throw a TypeError exception.
if (!Global::platform()->canBlockExecution(state.context())) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot suspend this thread");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Cannot suspend this thread");
}
}
// Let block be buffer.[[ArrayBufferData]].
@ -383,6 +396,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
if (isAsync) {
// Set promiseCapability to ! NewPromiseCapability(%Promise%).
promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
ASSERT(!state.hasPendingException());
// Set resultObject to ! OrdinaryObjectCreate(%Object.prototype%).
resultObject = new Object(state);
}
@ -406,6 +420,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(false), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
// Perform ! CreateDataPropertyOrThrow(resultObject, "value", "not-equal").
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(state.context()->staticStrings().lazyNotEqual().string(), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return resultObject.
return Value(resultObject.value());
}
@ -418,6 +433,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(false), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
// Perform ! CreateDataPropertyOrThrow(resultObject, "value", "timed-out").
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(state.context()->staticStrings().lazyTimedOut().string(), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return resultObject.
return Value(resultObject.value());
}
@ -478,6 +494,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(promiseCapability.m_promise, ObjectPropertyDescriptor::PresentAttribute::AllPresent));
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(resultObject.value());
} else {
bool notified = true;
@ -514,9 +531,11 @@ static Value builtinAtomicsNotify(ExecutionState& state, Value thisValue, size_t
// Atomics.notify ( typedArray, index, count )
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0], true);
RETURN_VALUE_IF_PENDING_EXCEPTION
TypedArrayObject* typedArray = argv[0].asObject()->asTypedArrayObject();
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
size_t indexedPosition = validateAtomicAccess(state, typedArray, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
double c;
// 3. If count is undefined, let c be +∞.
if (argv[2].isUndefined()) {
@ -579,30 +598,14 @@ static Value builtinAtomicsIsLockFree(ExecutionState& state, Value thisValue, si
#endif
}
// https://tc39.es/proposal-atomics-microwait/#Atomics.pause
static Value builtinAtomicsPause(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// 1. If N is neither undefined nor an integral Number, throw a TypeError exception.
Value N = argc ? argv[0] : Value();
if (!N.isUndefined() && (!N.isNumber() || !isIntegralNumber(N.asNumber()))) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
// 2. If the execution environment of the ECMAScript implementation supports signaling to the operating system or CPU that the current executing code is in a spin-wait loop,
// such as executing a pause CPU instruction, send that signal. When N is not undefined, it determines the number of times that signal is sent.
// The number of times the signal is sent for an integral Number N is less than or equal to the number times it is sent for N + 1 if both N and N + 1 have the same sign.
// TODO use number input
YIELD_PROCESSOR;
// 3. Return undefined.
return Value();
}
void GlobalObject::initializeAtomics(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->atomics(); }, nullptr);
return self->asGlobalObject()->atomics();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Atomics), nativeData, Value(Value::EmptyValue));
}
@ -654,9 +657,6 @@ void GlobalObject::installAtomics(ExecutionState& state)
m_atomics->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().notify),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().notify, builtinAtomicsNotify, 3, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_atomics->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().pause),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().pause, builtinAtomicsPause, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Atomics),
ObjectPropertyDescriptor(m_atomics, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}

View file

@ -35,16 +35,17 @@ static Value builtinBigIntConstructor(ExecutionState& state, Value thisValue, si
{
// If NewTarget is not undefined, throw a TypeError exception.
if (newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "illegal constructor BigInt");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "illegal constructor BigInt");
}
// Let prim be ? ToPrimitive(value, hint Number).
Value prim = argv[0].toPrimitive(state, Value::PreferNumber);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If Type(prim) is Number, return ? NumberToBigInt(prim).
if (prim.isNumber()) {
// NumberToBigInt(prim)
// If IsInteger(number) is false, throw a RangeError exception.
if (!prim.isInteger(state)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "The value you input to BigInt constructor is not integer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "The value you input to BigInt constructor is not integer");
}
double numValue = prim.asNumber();
if ((numValue > (double)std::numeric_limits<int64_t>::max()) || (numValue < (double)std::numeric_limits<int64_t>::min())) {
@ -61,7 +62,9 @@ static Value builtinBigIntConstructor(ExecutionState& state, Value thisValue, si
return new BigInt((int64_t)numValue);
} else {
// Otherwise, return ? ToBigInt(value).
return prim.toBigInt(state);
BigInt* result = argv[0].toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return result;
}
}
@ -69,11 +72,13 @@ static Value builtinBigIntAsUintN(ExecutionState& state, Value thisValue, size_t
{
// Let bits be ? ToIndex(bits).
auto bits = argv[0].toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (bits == Value::InvalidIndexValue) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
}
// Let bigint be ? ToBigInt(bigint).
BigInt* bigint = argv[1].toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return a BigInt representing bigint modulo 2bits.
bf_t mask, r;
bf_init(ThreadLocal::bfContext(), &mask);
@ -91,11 +96,13 @@ static Value builtinBigIntAsIntN(ExecutionState& state, Value thisValue, size_t
{
// Let bits be ? ToIndex(bits).
auto bits = argv[0].toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (bits == Value::InvalidIndexValue) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
}
// Let bigint be ? ToBigInt(bigint).
BigInt* bigint = argv[1].toBigInt(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return a BigInt representing bigint modulo 2bits.
bf_t mask, r;
bf_init(ThreadLocal::bfContext(), &mask);
@ -124,18 +131,18 @@ static Value builtinBigIntAsIntN(ExecutionState& state, Value thisValue, size_t
// Assert: Type(value.[[BigIntData]]) is BigInt.
// Return value.[[BigIntData]].
// Throw a TypeError exception.
#define RESOLVE_THIS_BINDING_TO_BIGINT(NAME, OBJ, BUILT_IN_METHOD) \
BigInt* NAME = nullptr; \
if (thisValue.isObject()) { \
if (!thisValue.asObject()->isBigIntObject()) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
NAME = thisValue.asObject()->asBigIntObject()->primitiveValue(); \
} else if (thisValue.isBigInt()) { \
NAME = thisValue.asBigInt(); \
} else { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
return Value(); \
#define RESOLVE_THIS_BINDING_TO_BIGINT(NAME, OBJ, BUILT_IN_METHOD) \
BigInt* NAME = nullptr; \
if (thisValue.isObject()) { \
if (!thisValue.asObject()->isBigIntObject()) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
NAME = thisValue.asObject()->asBigIntObject()->primitiveValue(); \
} else if (thisValue.isBigInt()) { \
NAME = thisValue.asBigInt(); \
} else { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
return Value(); \
}
static Value builtinBigIntToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -146,7 +153,7 @@ static Value builtinBigIntToString(ExecutionState& state, Value thisValue, size_
if (argc > 0 && !argv[0].isUndefined()) {
radix = argv[0].toInteger(state);
if (radix < 2 || radix > 36) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
}
}
@ -175,12 +182,15 @@ static Value builtinBigIntToLocaleString(ExecutionState& state, Value thisValue,
ObjectGetResult toStrFuncGetResult = state.context()->globalObject()->bigIntProxyObject()->get(state, ObjectPropertyName(state.context()->staticStrings().toString));
if (toStrFuncGetResult.hasValue()) {
Value toStrFunc = toStrFuncGetResult.value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (toStrFunc.isCallable()) {
// toLocaleString() ignores the first argument, unlike toString()
return Object::call(state, toStrFunc, thisObject, 0, argv);
Value result = Object::call(state, toStrFunc, thisObject, 0, argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
return result;
}
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().BigInt.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().BigInt.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
RELEASE_ASSERT_NOT_REACHED();
return Value();
#endif
@ -188,9 +198,12 @@ static Value builtinBigIntToLocaleString(ExecutionState& state, Value thisValue,
void GlobalObject::initializeBigInt(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->bigInt(); }, nullptr);
return self->asGlobalObject()->bigInt();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().BigInt), nativeData, Value(Value::EmptyValue));
}

View file

@ -27,13 +27,14 @@ namespace Escargot {
static Value builtinBooleanConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
bool primitiveVal = argv[0].toBoolean();
bool primitiveVal = argv[0].toBoolean(state);
if (!newTarget.hasValue()) {
return Value(primitiveVal);
} else {
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->booleanPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
BooleanObject* boolObj = new BooleanObject(state, proto, primitiveVal);
return boolObj;
}
@ -46,7 +47,7 @@ static Value builtinBooleanValueOf(ExecutionState& state, Value thisValue, size_
} else if (thisValue.isObject() && thisValue.asObject()->isBooleanObject()) {
return Value(thisValue.asPointerValue()->asBooleanObject()->primitiveValue());
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
RELEASE_ASSERT_NOT_REACHED();
}
@ -57,15 +58,18 @@ static Value builtinBooleanToString(ExecutionState& state, Value thisValue, size
} else if (thisValue.isObject() && thisValue.asObject()->isBooleanObject()) {
return Value(thisValue.asPointerValue()->asBooleanObject()->primitiveValue()).toString(state);
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
RELEASE_ASSERT_NOT_REACHED();
}
void GlobalObject::initializeBoolean(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->boolean(); }, nullptr);
return self->asGlobalObject()->boolean();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Boolean), nativeData, Value(Value::EmptyValue));
}

View file

@ -27,7 +27,6 @@
namespace Escargot {
#define FOR_EACH_DATAVIEW_TYPES(F) \
F(Float16) \
F(Float32) \
F(Float64) \
F(Int8) \
@ -41,100 +40,66 @@ namespace Escargot {
static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// If NewTarget is undefined, throw a TypeError exception.
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
}
// Perform ? RequireInternalSlot(buffer, [[ArrayBufferData]]).
if (!(argv[0].isObject() && argv[0].asPointerValue()->isArrayBuffer())) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_ThisNotArrayBufferObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotArrayBufferObject);
}
ArrayBuffer* buffer = argv[0].asObject()->asArrayBuffer();
// Let offset be ? ToIndex(byteOffset).
double offset = 0;
double byteOffset = 0;
if (argc >= 2) {
offset = argv[1].toIndex(state);
if (offset == Value::InvalidIndexValue) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
Value& val = argv[1];
byteOffset = val.toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (byteOffset == Value::InvalidIndexValue) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
}
}
// If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if (buffer->isDetachedBuffer()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), "%s: ArrayBuffer is detached buffer");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, "%s: ArrayBuffer is detached buffer");
}
// Let bufferByteLength be ArrayBufferByteLength(buffer, seq-cst).
auto bufferByteLegnth = buffer->byteLength();
// If offset > bufferByteLength, throw a RangeError exception.
if (offset > bufferByteLegnth) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
double bufferByteLength = buffer->byteLength();
if (byteOffset > bufferByteLength) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
}
// Let bufferIsFixedLength be IsFixedLengthArrayBuffer(buffer).
bool bufferIsFixedLength = buffer->isFixedLengthArrayBuffer();
// If byteLength is undefined, then
Optional<Value::ValueIndex> viewByteLength;
if (argc < 3 || argv[2].isUndefined()) {
// If bufferIsFixedLength is true, then
if (bufferIsFixedLength) {
// Let viewByteLength be bufferByteLength - offset.
viewByteLength = bufferByteLegnth - offset;
} else {
// Else
// Let viewByteLength be auto.
}
} else {
// Else,
// Let viewByteLength be ? ToIndex(byteLength).
viewByteLength = argv[2].toIndex(state);
if (viewByteLength.value() == Value::InvalidIndexValue) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
}
// If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
if (offset + viewByteLength.value() > bufferByteLegnth) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
double byteLength = bufferByteLength - byteOffset;
if (argc >= 3) {
Value& val = argv[2];
if (!val.isUndefined()) {
byteLength = val.toIndex(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (byteOffset + byteLength > bufferByteLength || byteLength == Value::InvalidIndexValue) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
}
}
}
// Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataView.prototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »).
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->dataViewPrototype();
});
ArrayBufferView* O = new DataViewObject(state, proto);
RETURN_VALUE_IF_PENDING_EXCEPTION
ArrayBufferView* obj = new DataViewObject(state, proto);
obj->setBuffer(buffer, byteOffset, byteLength);
// If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if (buffer->isDetachedBuffer()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), "%s: ArrayBuffer is detached buffer");
if (obj->buffer()->isDetachedBuffer()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_DetachedBuffer);
}
// Set bufferByteLength to ArrayBufferByteLength(buffer, seq-cst).
bufferByteLegnth = buffer->byteLength();
// If offset > bufferByteLength, throw a RangeError exception.
if (offset > bufferByteLegnth) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
}
// If byteLength is not undefined, then
if (argc >= 3 && !argv[2].isUndefined()) {
// If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
if (offset + viewByteLength.value() > bufferByteLegnth) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString(), ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
}
}
// Set O.[[ViewedArrayBuffer]] to buffer.
// Set O.[[ByteLength]] to viewByteLength.
// Set O.[[ByteOffset]] to offset.
// Return O.
O->setBuffer(buffer, offset, viewByteLength ? viewByteLength.value() : bufferByteLegnth - offset, 0, argc < 3);
return O;
return obj;
}
#define DECLARE_DATAVIEW_GETTER(Name) \
static Value builtinDataViewGet##Name(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
{ \
Object* thisObject = thisValue.toObject(state); \
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, DataView, get##Name); \
if (!(thisObject->isDataViewObject())) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
true, state.context()->staticStrings().get##Name.string(), \
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
true, state.context()->staticStrings().get##Name.string(), \
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
} \
if (argc < 2) { \
return thisObject->asDataViewObject()->getViewValue(state, argv[0], Value(false), TypedArrayType::Name); \
@ -146,18 +111,17 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
#define DECLARE_DATAVIEW_SETTER(Name) \
static Value builtinDataViewSet##Name(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
{ \
Object* thisObject = thisValue.toObject(state); \
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, DataView, get##Name); \
if (!(thisObject->isDataViewObject())) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
true, state.context()->staticStrings().set##Name.string(), \
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
true, state.context()->staticStrings().set##Name.string(), \
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
} \
if (argc < 3) { \
thisObject->asDataViewObject()->setViewValue(state, argv[0], Value(false), TypedArrayType::Name, argv[1]); \
return thisObject->asDataViewObject()->setViewValue(state, argv[0], Value(false), TypedArrayType::Name, argv[1]); \
} else { \
thisObject->asDataViewObject()->setViewValue(state, argv[0], argv[2], TypedArrayType::Name, argv[1]); \
return thisObject->asDataViewObject()->setViewValue(state, argv[0], argv[2], TypedArrayType::Name, argv[1]); \
} \
return Value(); \
}
FOR_EACH_DATAVIEW_TYPES(DECLARE_DATAVIEW_GETTER);
@ -171,35 +135,36 @@ static Value builtinDataViewBufferGetter(ExecutionState& state, Value thisValue,
return Value(buffer);
}
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.buffer called on incompatible receiver");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.buffer called on incompatible receiver");
RELEASE_ASSERT_NOT_REACHED();
}
static Value builtinDataViewByteLengthGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer())) {
thisValue.asObject()->asDataViewObject()->throwTypeErrorIfDetached(state);
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer() && !thisValue.asObject()->asDataViewObject()->buffer()->isDetachedBuffer())) {
return Value(thisValue.asObject()->asArrayBufferView()->byteLength());
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.byteLength called on incompatible receiver");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.byteLength called on incompatible receiver");
RELEASE_ASSERT_NOT_REACHED();
}
static Value builtinDataViewByteOffsetGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer())) {
thisValue.asObject()->asDataViewObject()->throwTypeErrorIfDetached(state);
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer() && !thisValue.asObject()->asDataViewObject()->buffer()->isDetachedBuffer())) {
return Value(thisValue.asObject()->asArrayBufferView()->byteOffset());
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.byteOffset called on incompatible receiver");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.byteOffset called on incompatible receiver");
RELEASE_ASSERT_NOT_REACHED();
}
void GlobalObject::initializeDataView(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->dataView(); }, nullptr);
return self->asGlobalObject()->dataView();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().DataView), nativeData, Value(Value::EmptyValue));
}

View file

@ -29,10 +29,6 @@
#include "intl/IntlDateTimeFormat.h"
#endif
#if defined(ENABLE_TEMPORAL)
#include "runtime/TemporalInstantObject.h"
#endif
namespace Escargot {
#define FOR_EACH_DATE_VALUES(F) \
@ -81,6 +77,7 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->datePrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
DateObject* thisObject = new DateObject(state, proto);
if (argc == 0) {
@ -96,13 +93,16 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
} else {
// Let v be ToPrimitive(value).
v = v.toPrimitive(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If Type(v) is String, then
if (v.isString()) {
thisObject->setTimeValue(state, v);
RETURN_VALUE_IF_PENDING_EXCEPTION
} else {
// Let tv be ToNumber(v).
double V = v.toNumber(state);
thisObject->setTimeValue(DateObject::timeClipToTime64(state, V));
RETURN_VALUE_IF_PENDING_EXCEPTION
thisObject->setTimeValue(DateObject::timeClip(state, V));
}
}
} else {
@ -113,6 +113,7 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
argc = (argc > 7) ? 7 : argc; // trim arguments so that they don't corrupt stack
for (size_t i = 0; i < argc; i++) {
args[i] = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
double year = args[0];
double month = args[1];
@ -142,9 +143,11 @@ static Value builtinDateNow(ExecutionState& state, Value thisValue, size_t argc,
static Value builtinDateParse(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Value str = argv[0].toPrimitive(state, Value::PreferString);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (str.isString()) {
DateObject d(state);
d.setTimeValue(state, str);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(Value::DoubleToIntConvertibleTestNeeds, d.primitiveValue());
}
return Value(Value::NanInit);
@ -157,6 +160,7 @@ static Value builtinDateUTC(ExecutionState& state, Value thisValue, size_t argc,
argc = (argc > 7) ? 7 : argc; // trim arguments so that they don't corrupt stack
for (size_t i = 0; i < argc; i++) {
args[i] = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
double year = args[0];
double month = args[1];
@ -182,10 +186,10 @@ static Value builtinDateUTC(ExecutionState& state, Value thisValue, size_t argc,
return Value(Value::DoubleToIntConvertibleTestNeeds, d.primitiveValue());
}
#define RESOLVE_THIS_BINDING_TO_DATE(NAME, OBJ, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isDateObject()) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisNotDateObject); \
} \
#define RESOLVE_THIS_BINDING_TO_DATE(NAME, OBJ, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isDateObject()) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisNotDateObject); \
} \
DateObject* NAME = thisValue.asObject()->asDateObject();
static Value builtinDateGetTime(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -220,23 +224,21 @@ static Value builtinDateToTimeString(ExecutionState& state, Value thisValue, siz
}
#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
#define INTL_DATE_TIME_FORMAT_FORMAT(REQUIRED, DEFUALT) \
double x = thisObject->primitiveValue(); \
if (std::isnan(x)) { \
return new ASCIIStringFromExternalMemory("Invalid Date"); \
} \
Value locales, options; \
if (argc >= 1) { \
locales = argv[0]; \
} \
if (argc >= 2) { \
options = argv[1]; \
} \
auto dateTimeOption = IntlDateTimeFormatObject:: \
toDateTimeOptions(state, options, String::fromASCII(REQUIRED), String::fromASCII(DEFUALT)) \
.first; \
IntlDateTimeFormatObject* dateFormat = new IntlDateTimeFormatObject(state, locales, dateTimeOption); \
auto result = dateFormat->format(state, x); \
#define INTL_DATE_TIME_FORMAT_FORMAT(REQUIRED, DEFUALT) \
double x = thisObject->primitiveValue(); \
if (std::isnan(x)) { \
return new ASCIIString("Invalid Date"); \
} \
Value locales, options; \
if (argc >= 1) { \
locales = argv[0]; \
} \
if (argc >= 2) { \
options = argv[1]; \
} \
auto dateTimeOption = IntlDateTimeFormatObject::toDateTimeOptions(state, options, String::fromASCII(REQUIRED), String::fromASCII(DEFUALT)); \
IntlDateTimeFormatObject* dateFormat = new IntlDateTimeFormatObject(state, locales, dateTimeOption); \
auto result = dateFormat->format(state, x); \
return new UTF16String(result.data(), result.length());
#endif
@ -284,14 +286,16 @@ static Value builtinDateToISOString(ExecutionState& state, Value thisValue, size
static Value builtinDateToJSON(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Object* thisObject = thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Date, toJSON);
Value tv = Value(thisObject).toPrimitive(state, Value::PreferNumber);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (tv.isNumber() && (std::isnan(tv.asNumber()) || std::isinf(tv.asNumber()))) {
return Value(Value::Null);
}
Value isoFunc = thisObject->get(state, ObjectPropertyName(state.context()->staticStrings().toISOString)).value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Object::call(state, isoFunc, thisObject, 0, nullptr);
}
@ -318,19 +322,13 @@ static Value builtinDateSetHelper(ExecutionState& state, DateSetterType setterTy
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, name);
DateObject* d = thisObject;
// Read the current [[DateValue]] first (before any ToNumber conversions)
// To keep a record of the original state
double originalDateValue = d->primitiveValue();
bool isOriginalDateValid = d->isValid();
if (setterType == DateSetterType::Day && length == 3) {
// setFullYear, setUTCFullYear case
if (!isOriginalDateValid) {
d->setTimeValue(DateObject::timeClipToTime64(state, 0));
d->setTimeValue(d->getTimezoneOffset(state) * TimeConstant::MsPerMinute);
originalDateValue = d->primitiveValue();
isOriginalDateValid = true;
if (!(d->isValid())) {
d->setTimeValue(DateObject::timeClip(state, 0));
d->setTimeValue(d->getTimezoneOffset(state) * const_Date_msPerMinute);
}
ASSERT(d->isValid());
}
if (argc < 1) {
@ -338,10 +336,9 @@ static Value builtinDateSetHelper(ExecutionState& state, DateSetterType setterTy
return Value(Value::NanInit);
}
// Read date components from original state (before ToNumber calls)
double year = 0, month = 0, date = 0, hour = 0, minute = 0, second = 0, millisecond = 0;
if (isOriginalDateValid) {
if (d->isValid()) {
if (!utc) {
year = d->getFullYear(state);
month = d->getMonth(state);
@ -363,7 +360,8 @@ static Value builtinDateSetHelper(ExecutionState& state, DateSetterType setterTy
}
}
// Convert arguments to numbers (this may cause side effects)
bool convertToUTC = !utc;
switch (setterType) {
case DateSetterType::Day:
if ((length >= 3) && (argc > length - 3))
@ -387,16 +385,10 @@ static Value builtinDateSetHelper(ExecutionState& state, DateSetterType setterTy
RELEASE_ASSERT_NOT_REACHED();
}
// Check if original date value was NaN
if (std::isnan(originalDateValue)) {
return Value(Value::NanInit);
}
bool convertToUTC = !utc;
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(!isInValidRange(year, month, date, hour, minute, second, millisecond))) {
d->setTimeValueAsNaN();
} else {
} else if (d->isValid()) {
d->setTimeValue(state, year, month, date, hour, minute, second, millisecond, convertToUTC);
}
@ -415,7 +407,10 @@ static Value builtinDateSetTime(ExecutionState& state, Value thisValue, size_t a
{
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, setTime);
if (argc > 0) {
thisObject->setTimeValue(DateObject::timeClipToTime64(state, argv[0].toNumber(state)));
double num = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
thisObject->setTimeValue(DateObject::timeClip(state, num));
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(Value::DoubleToIntConvertibleTestNeeds, thisObject->primitiveValue());
} else {
thisObject->setTimeValueAsNaN();
@ -439,8 +434,8 @@ static Value builtinDateSetYear(ExecutionState& state, Value thisValue, size_t a
DateObject* d = thisObject;
if (!(d->isValid())) {
d->setTimeValue(DateObject::timeClipToTime64(state, 0));
d->setTimeValue(d->getTimezoneOffset(state) * TimeConstant::MsPerMinute);
d->setTimeValue(DateObject::timeClip(state, 0));
d->setTimeValue(d->getTimezoneOffset(state) * const_Date_msPerMinute);
}
ASSERT(d->isValid());
@ -451,6 +446,16 @@ static Value builtinDateSetYear(ExecutionState& state, Value thisValue, size_t a
double y;
int month, date, hour, minute, second, millisecond;
// Let y be ToNumber(year).
y = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If y is NaN, set the [[DateValue]] internal slot of this Date object to NaN and return NaN.
if (std::isnan(y)) {
d->setTimeValueAsNaN();
return Value(Value::NanInit);
}
month = d->getMonth(state);
date = d->getDate(state);
hour = d->getHours(state);
@ -458,14 +463,6 @@ static Value builtinDateSetYear(ExecutionState& state, Value thisValue, size_t a
second = d->getSeconds(state);
millisecond = d->getMilliseconds(state);
// Let y be ToNumber(year).
y = argv[0].toNumber(state);
// If y is NaN, set the [[DateValue]] internal slot of this Date object to NaN and return NaN.
if (std::isnan(y)) {
d->setTimeValueAsNaN();
return Value(Value::NanInit);
}
double yyyy;
double yAsInteger = Value(Value::DoubleToIntConvertibleTestNeeds, y).toInteger(state);
// If y is not NaN and 0 ≤ ToInteger(y) ≤ 99, let yyyy be ToInteger(y) + 1900.
@ -476,7 +473,9 @@ static Value builtinDateSetYear(ExecutionState& state, Value thisValue, size_t a
yyyy = y;
}
d->setTimeValue(state, yyyy, month, date, hour, minute, second, millisecond);
if (d->isValid()) {
d->setTimeValue(state, yyyy, month, date, hour, minute, second, millisecond);
}
return Value(Value::DoubleToIntConvertibleTestNeeds, d->primitiveValue());
}
@ -495,8 +494,8 @@ static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size
Value O = thisValue;
// If Type(O) is not Object, throw a TypeError exception.
if (!O.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
}
bool tryFirstIsString = false;
// If hint is the String value "string" or the String value "default", then
@ -509,8 +508,8 @@ static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size
tryFirstIsString = false;
} else {
// Else, throw a TypeError exception.
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
// Return ? OrdinaryToPrimitive(O, tryFirst).
if (tryFirstIsString) {
@ -520,19 +519,14 @@ static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size
}
}
#if defined(ENABLE_TEMPORAL)
static Value builtinDateToTemporalInstant(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, lazyToTemporalInstant());
return thisObject->toTemporalInstant(state);
}
#endif
void GlobalObject::initializeDate(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->date(); }, nullptr);
return self->asGlobalObject()->date();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Date), nativeData, Value(Value::EmptyValue));
}
@ -623,12 +617,6 @@ void GlobalObject::installDate(ExecutionState& state)
FOR_EACH_DATE_VALUES(DATE_DEFINE_SETTER);
#if defined(ENABLE_TEMPORAL)
m_datePrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyToTemporalInstant()),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().lazyToTemporalInstant(), builtinDateToTemporalInstant, 0, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
#endif
m_date->setFunctionPrototype(state, m_datePrototype);
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Date),

View file

@ -52,26 +52,27 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->errorPrototype();
});
#if defined(ENABLE_EXTENDED_API)
ErrorObject* obj = new ErrorObject(state, proto, String::emptyString(), true, state.context()->vmInstance()->isErrorCreationCallbackRegistered());
#else
ErrorObject* obj = new ErrorObject(state, proto, String::emptyString());
#endif
RETURN_VALUE_IF_PENDING_EXCEPTION
ErrorObject* obj = new ErrorObject(state, proto, String::emptyString);
Value message = argv[0];
if (!message.isUndefined()) {
obj->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message,
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
}
Value options = argc > 1 ? argv[1] : Value();
installErrorCause(state, obj, options);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) {
state.context()->vmInstance()->triggerErrorCreationCallback(state, obj);
}
return obj;
}
#if defined(ENABLE_EXTENDED_API)
#define DEFINE_ERROR_CTOR(errorName, lowerCaseErrorName) \
static Value builtin##errorName##ErrorConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
{ \
@ -81,37 +82,22 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* { \
return constructorRealm->globalObject()->lowerCaseErrorName##ErrorPrototype(); \
}); \
ErrorObject* obj = new errorName##ErrorObject(state, proto, String::emptyString(), true, state.context()->vmInstance()->isErrorCreationCallbackRegistered()); \
RETURN_VALUE_IF_PENDING_EXCEPTION \
ErrorObject* obj = new errorName##ErrorObject(state, proto, String::emptyString); \
Value message = argv[0]; \
if (!message.isUndefined()) { \
obj->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message, \
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
RETURN_VALUE_IF_PENDING_EXCEPTION \
} \
Value options = argc > 1 ? argv[1] : Value(); \
installErrorCause(state, obj, options); \
RETURN_VALUE_IF_PENDING_EXCEPTION \
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) { \
state.context()->vmInstance()->triggerErrorCreationCallback(state, obj); \
} \
return obj; \
}
#else
#define DEFINE_ERROR_CTOR(errorName, lowerCaseErrorName) \
static Value builtin##errorName##ErrorConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
{ \
if (!newTarget.hasValue()) { \
newTarget = state.resolveCallee(); \
} \
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* { \
return constructorRealm->globalObject()->lowerCaseErrorName##ErrorPrototype(); \
}); \
ErrorObject* obj = new errorName##ErrorObject(state, proto, String::emptyString()); \
Value message = argv[0]; \
if (!message.isUndefined()) { \
obj->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message, \
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
} \
Value options = argc > 1 ? argv[1] : Value(); \
installErrorCause(state, obj, options); \
return obj; \
}
#endif
DEFINE_ERROR_CTOR(Reference, reference);
DEFINE_ERROR_CTOR(Type, type);
@ -130,13 +116,8 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->aggregateErrorPrototype();
});
#if defined(ENABLE_EXTENDED_API)
ErrorObject* O = new AggregateErrorObject(state, proto, String::emptyString(), true, state.context()->vmInstance()->isErrorCreationCallbackRegistered());
#else
ErrorObject* O = new AggregateErrorObject(state, proto, String::emptyString());
#endif
RETURN_VALUE_IF_PENDING_EXCEPTION
ErrorObject* O = new AggregateErrorObject(state, proto, String::emptyString);
Value message = argv[1];
// If message is not undefined, then
if (!message.isUndefined()) {
@ -145,65 +126,45 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV
// Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
O->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message,
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
}
// Perform ? InstallErrorCause(O, options).
Value options = argc > 2 ? argv[2] : Value();
installErrorCause(state, O, options);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let errorsList be ? IterableToList(errors).
auto errorsList = IteratorObject::iterableToList(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Perform ! DefinePropertyOrThrow(O, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errorsList) }).
O->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")),
ObjectPropertyDescriptor(Value(Object::createArrayFromList(state, errorsList.size(), errorsList.data())), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) {
state.context()->vmInstance()->triggerErrorCreationCallback(state, O);
}
// Return O.
return O;
}
static Value builtinSuppressedErrorConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!newTarget.hasValue()) {
newTarget = state.resolveCallee();
}
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->suppressedErrorPrototype();
});
String* message = String::emptyString();
if (!argv[2].isUndefined()) {
message = argv[2].toString(state);
}
#if defined(ENABLE_EXTENDED_API)
ErrorObject* O = new SuppressedErrorObject(state, proto, message, true, state.context()->vmInstance()->isErrorCreationCallbackRegistered(), argv[0], argv[1]);
#else
ErrorObject* O = new SuppressedErrorObject(state, proto, message, true, false, argv[0], argv[1]);
#endif
// test/built-ins/NativeErrors/SuppressedError/message-undefined-no-prop.js
if (argv[2].isUndefined()) {
O->deleteOwnProperty(state, state.context()->staticStrings().message);
}
return O;
}
static Value builtinErrorThrowTypeError(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "");
return Value();
}
static Value builtinErrorToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!thisValue.isObject())
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Error.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Error.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
Object* o = thisValue.toObject(state);
if (!state.context()->toStringRecursionPreventer()->canInvokeToString(o)) {
return String::emptyString();
return String::emptyString;
}
ToStringRecursionPreventerItemAutoHolder holder(state, o);
@ -217,7 +178,7 @@ static Value builtinErrorToString(ExecutionState& state, Value thisValue, size_t
Value message = o->get(state, state.context()->staticStrings().message).value(state, o);
String* messageStr;
if (message.isUndefined()) {
messageStr = String::emptyString();
messageStr = String::emptyString;
} else {
messageStr = message.toString(state);
}
@ -231,32 +192,23 @@ static Value builtinErrorToString(ExecutionState& state, Value thisValue, size_t
}
StringBuilder builder;
builder.appendString(nameStr, &state);
builder.appendString(": ", &state);
builder.appendString(messageStr, &state);
builder.appendString(nameStr);
builder.appendString(": ");
builder.appendString(messageStr);
return builder.finalize(&state);
}
// https://tc39.es/ecma262/#sec-error.iserror
static Value builtinErrorIsError(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// 1. If arg is not an Object, return false.
// 2. If arg does not have an [[ErrorData]] internal slot, return false.
if (!argv[0].isObject() || !argv[0].asObject()->isErrorObject()) {
return Value(false);
}
// 3. Return true.
return Value(true);
}
void GlobalObject::initializeError(ExecutionState& state)
{
#define DEFINE_ERROR_INIT(errorname, bname) \
{ \
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value { \
#define DEFINE_ERROR_INIT(errorname, bname) \
{ \
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, \
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value { \
ASSERT(self->isGlobalObject()); \
return self->asGlobalObject()->errorname##Error(); }, nullptr); \
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().bname##Error), nativeData, Value(Value::EmptyValue)); \
return self->asGlobalObject()->errorname##Error(); \
}, \
nullptr); \
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().bname##Error), nativeData, Value(Value::EmptyValue)); \
}
DEFINE_ERROR_INIT(reference, Reference);
@ -266,12 +218,14 @@ void GlobalObject::initializeError(ExecutionState& state)
DEFINE_ERROR_INIT(uri, URI);
DEFINE_ERROR_INIT(eval, Eval);
DEFINE_ERROR_INIT(aggregate, Aggregate);
DEFINE_ERROR_INIT(suppressed, Suppressed);
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->error(); }, nullptr);
return self->asGlobalObject()->error();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Error), nativeData, Value(Value::EmptyValue));
}
}
@ -281,10 +235,6 @@ void GlobalObject::installError(ExecutionState& state)
m_error = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().Error, builtinErrorConstructor, 1), NativeFunctionObject::__ForBuiltinConstructor__);
m_error->setGlobalIntrinsicObject(state);
m_error->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().isError),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().isError, builtinErrorIsError, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_errorPrototype = new PrototypeObject(state);
m_errorPrototype->setGlobalIntrinsicObject(state, true);
@ -292,7 +242,7 @@ void GlobalObject::installError(ExecutionState& state)
m_errorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_error, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_errorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().message, ObjectPropertyDescriptor(String::emptyString(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_errorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().message, ObjectPropertyDescriptor(String::emptyString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_errorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().name, ObjectPropertyDescriptor(state.context()->staticStrings().Error.string(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto errorToStringFn = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().toString, builtinErrorToString, 0, NativeFunctionInfo::Strict));
m_errorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().toString, ObjectPropertyDescriptor(errorToStringFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
@ -305,7 +255,7 @@ void GlobalObject::installError(ExecutionState& state)
m_throwTypeError->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().length),
ObjectPropertyDescriptor(Value(0), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
m_throwTypeError->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().name),
ObjectPropertyDescriptor(String::emptyString(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
ObjectPropertyDescriptor(String::emptyString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
m_throwTypeError->preventExtensions(state);
m_throwerGetterSetterData = new JSGetterSetter(m_throwTypeError, m_throwTypeError);
@ -316,7 +266,7 @@ void GlobalObject::installError(ExecutionState& state)
m_##errorname##ErrorPrototype = new PrototypeObject(state, m_errorPrototype); \
m_##errorname##ErrorPrototype->setGlobalIntrinsicObject(state, true); \
m_##errorname##ErrorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().constructor, ObjectPropertyDescriptor(m_##errorname##Error, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
m_##errorname##ErrorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().message, ObjectPropertyDescriptor(String::emptyString(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
m_##errorname##ErrorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().message, ObjectPropertyDescriptor(String::emptyString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
m_##errorname##ErrorPrototype->directDefineOwnProperty(state, state.context()->staticStrings().name, ObjectPropertyDescriptor(state.context()->staticStrings().bname##Error.string(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
m_##errorname##Error->setFunctionPrototype(state, m_##errorname##ErrorPrototype); \
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().bname##Error), \
@ -329,7 +279,6 @@ void GlobalObject::installError(ExecutionState& state)
DEFINE_ERROR(uri, URI, 1);
DEFINE_ERROR(eval, Eval, 1);
DEFINE_ERROR(aggregate, Aggregate, 2);
DEFINE_ERROR(suppressed, Suppressed, 3);
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Error),
ObjectPropertyDescriptor(m_error, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -26,26 +26,26 @@
namespace Escargot {
#define RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(NAME, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isFinalizationRegistryObject()) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().FinalizationRegistry.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
#define RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(NAME, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isFinalizationRegistryObject()) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().FinalizationRegistry.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
FinalizationRegistryObject* NAME = thisValue.asObject()->asFinalizationRegistryObject();
static Value builtinFinalizationRegistryConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
}
if (!argv[0].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "cleanup Callback is not callable");
if (argc == 0 || !argv[0].isCallable()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "cleanup Callback is not callable");
}
// Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]] »).
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->finalizationRegistryPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
return new FinalizationRegistryObject(state, proto, argv[0].asObject(), state.resolveCallee()->getFunctionRealm(state));
}
@ -54,32 +54,32 @@ static Value builtinfinalizationRegistryRegister(ExecutionState& state, Value th
{
RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(finalRegistry, stringRegister);
if (!argv[0].canBeHeldWeakly(state.context()->vmInstance())) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "target is not object");
if (argc == 0 || !argv[0].isObject()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "target is not object");
}
if (argv[0] == argv[1]) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "target and heldValue is the same");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "target and heldValue is the same");
}
Optional<PointerValue*> unregisterToken;
Value tokenValue = argc >= 3 ? argv[2] : Value();
if (tokenValue.canBeHeldWeakly(state.context()->vmInstance())) {
unregisterToken = argv[2].asPointerValue();
} else if (!tokenValue.isUndefined()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "unregisterToken is not undefined");
Optional<Object*> unregisterToken;
if (argc >= 3) {
if (argv[2].isObject()) {
unregisterToken = argv[2].asObject();
} else if (!argv[2].isUndefined()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "unregisterToken is not undefined");
}
}
finalRegistry->setCell(argv[0].asPointerValue(), argv[1], unregisterToken);
finalRegistry->setCell(argv[0].asObject(), argv[1], unregisterToken);
return Value();
}
static Value builtinfinalizationRegistryUnregister(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(finalRegistry, unregister);
if (!argv[0].canBeHeldWeakly(state.context()->vmInstance())) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "unregisterToken is not object");
if (argc == 0 || !argv[0].isObject()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "unregisterToken is not object");
}
return Value(finalRegistry->deleteCell(argv[0].asPointerValue()));
return Value(finalRegistry->deleteCell(argv[0].asObject()));
}
static Value builtinfinalizationRegistryCleanupSome(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -90,7 +90,7 @@ static Value builtinfinalizationRegistryCleanupSome(ExecutionState& state, Value
Object* callback = nullptr;
if (argc && !argv[0].isUndefined()) {
if (!argv[0].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "callback is not callable");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "callback is not callable");
}
callback = argv[0].asObject();
}
@ -102,9 +102,12 @@ static Value builtinfinalizationRegistryCleanupSome(ExecutionState& state, Value
void GlobalObject::initializeFinalizationRegistry(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->finalizationRegistry(); }, nullptr);
return self->asGlobalObject()->finalizationRegistry();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().FinalizationRegistry), nativeData, Value(Value::EmptyValue));
}

View file

@ -40,14 +40,15 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
Value checkMSG = state.context()->securityPolicyCheckCallback()(state, false);
if (!checkMSG.isEmpty()) {
ASSERT(checkMSG.isString());
ErrorObject::throwBuiltinError(state, ErrorCode::EvalError, checkMSG.asString());
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::EvalError, checkMSG.asString());
return Value();
}
}
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString());
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, false, false);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
if (!newTarget.hasValue()) {
@ -56,6 +57,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->functionPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false);
@ -81,7 +83,7 @@ static Value builtinFunctionToString(ExecutionState& state, Value thisValue, siz
while (length > 0 && EscargotLexer::isWhiteSpaceOrLineTerminator(src[length - 1])) {
length--;
}
builder.appendString(new StringView(src, 0, length), &state);
builder.appendString(new StringView(src, 0, length));
} else {
ASSERT(fn->isNativeFunctionObject());
builder.appendString("function ");
@ -100,14 +102,14 @@ static Value builtinFunctionToString(ExecutionState& state, Value thisValue, siz
}
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
return Value();
}
static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!thisValue.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
}
Value thisArg = argv[0];
Value argArray = argv[1];
@ -118,6 +120,7 @@ static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t
// TODO
} else {
argList = Object::createListFromArrayLike(state, argArray);
RETURN_VALUE_IF_PENDING_EXCEPTION
arrlen = argList.size();
arguments = argList.data();
}
@ -128,7 +131,7 @@ static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t
static Value builtinFunctionCall(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!thisValue.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
}
Value thisArg = argv[0];
size_t arrlen = argc > 0 ? argc - 1 : 0;
@ -145,7 +148,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
{
// If IsCallable(Target) is false, throw a TypeError exception.
if (!thisValue.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().bind.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().bind.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
}
// Let Target be the this value.
@ -155,7 +158,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
Value boundThis = argv[0];
size_t boundArgc = (argc > 0) ? argc - 1 : 0;
Value* boundArgv = (boundArgc > 0) ? argv + 1 : nullptr;
// BoundFunctionObject* F = new BoundFunctionObject(state, thisValue, boundThis, boundArgc, boundArgv);
//BoundFunctionObject* F = new BoundFunctionObject(state, thisValue, boundThis, boundArgc, boundArgv);
// Let targetHasLength be HasOwnProperty(Target, "length").
bool targetHasLength = target->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().length));
@ -164,6 +167,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
if (targetHasLength) {
// Let targetLen be Get(Target, "length").
Value targetLen = target->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, target);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If Type(targetLen) is not Number, let L be 0.
// Else Let targetLen be ToInteger(targetLen).
// Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
@ -177,16 +181,17 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
// Let targetName be Get(Target, "name").
Value targetName = target->get(state, ObjectPropertyName(state.context()->staticStrings().name)).value(state, target);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If Type(targetName) is not String, let targetName be the empty string.
if (!targetName.isString()) {
targetName = String::emptyString();
targetName = String::emptyString;
}
StringBuilder builder;
builder.appendString("bound ");
builder.appendString(targetName.asString());
// F->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().name),
// ObjectPropertyDescriptor(Value(builder.finalize(&state)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
//F->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().name),
// ObjectPropertyDescriptor(Value(builder.finalize(&state)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
// Let F be BoundFunctionCreate(Target, thisArg, args).
// Let status be DefinePropertyOrThrow(F, "length", PropertyDescriptor {[[Value]]: L, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).
@ -200,7 +205,9 @@ static Value builtinFunctionHasInstanceOf(ExecutionState& state, Value thisValue
if (!thisValue.isObject()) {
return Value(false);
}
return Value(thisValue.asObject()->hasInstance(state, argv[0]));
Value result = Value(thisValue.asObject()->hasInstance(state, argv[0]));
RETURN_VALUE_IF_PENDING_EXCEPTION
return result;
}
static Value builtinCallerAndArgumentsGetterSetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -232,7 +239,7 @@ static Value builtinCallerAndArgumentsGetterSetter(ExecutionState& state, Value
}
if (needThrow) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "'caller' and 'arguments' restrict properties may not be accessed on strict mode functions or the arguments objects for calls to them");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "'caller' and 'arguments' restrict properties may not be accessed on strict mode functions or the arguments objects for calls to them");
}
bool inStrict = false;

View file

@ -30,8 +30,9 @@ namespace Escargot {
static Value builtinGeneratorFunction(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString());
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, false, false);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
if (!newTarget.hasValue()) {
@ -40,6 +41,7 @@ static Value builtinGeneratorFunction(ExecutionState& state, Value thisValue, si
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->generator();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
return new ScriptGeneratorFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
}
@ -71,15 +73,14 @@ void GlobalObject::installGenerator(ExecutionState& state)
// %GeneratorFunction% : The constructor of generator objects
m_generatorFunction = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().GeneratorFunction, builtinGeneratorFunction, 1), NativeFunctionObject::__ForBuiltinConstructor__);
m_generatorFunction->setGlobalIntrinsicObject(state);
m_generatorFunction->setPrototype(state, m_function);
// %Generator% : The initial value of the prototype property of %GeneratorFunction%
m_generator = new PrototypeObject(state, m_functionPrototype);
m_generator = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().GeneratorFunction, nullptr, 0, NativeFunctionInfo::Strict));
m_generator->setGlobalIntrinsicObject(state, true);
m_generatorFunction->setFunctionPrototype(state, m_generator);
// 25.2.3.1 The initial value of GeneratorFunction.prototype.constructor is the intrinsic object %GeneratorFunction%.
m_generator->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_generatorFunction, ObjectPropertyDescriptor::ConfigurablePresent));
m_generator->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_generatorFunction, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
{
ASSERT(!!m_callerAndArgumentsGetterSetter);
@ -100,7 +101,7 @@ void GlobalObject::installGenerator(ExecutionState& state)
// The initial value of the @@toStringTag property is the String value "GeneratorFunction"..
// This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
m_generator->directDefineOwnProperty(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(state.context()->staticStrings().GeneratorFunction.string(), ObjectPropertyDescriptor::ConfigurablePresent));
ObjectPropertyDescriptor(Value(state.context()->staticStrings().GeneratorFunction.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// The initial value of Generator.prototype.constructor is the intrinsic object %Generator%.
m_generatorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_generator, ObjectPropertyDescriptor::ConfigurablePresent));
@ -113,6 +114,6 @@ void GlobalObject::installGenerator(ExecutionState& state)
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().stringThrow, builtinGeneratorThrow, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// http://www.ecma-international.org/ecma-262/6.0/#sec-generatorfunction.prototype-@@tostringtag
m_generatorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(state.context()->staticStrings().Generator.string(), ObjectPropertyDescriptor::ConfigurablePresent));
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Generator.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}
} // namespace Escargot

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -21,9 +21,9 @@
#include "runtime/Context.h"
#include "runtime/GlobalObject.h"
#include "runtime/JSON.h"
#include "runtime/RawJSONObject.h"
#include "runtime/NativeFunctionObject.h"
#include "runtime/VMInstance.h"
#include "runtime/Value.h"
namespace Escargot {
@ -37,63 +37,14 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
return JSON::stringify(state, argv[0], argv[1], argv[2]);
}
// https://tc39.es/proposal-json-parse-with-source/#sec-json.rawjson
static Value builtinJSONRawJSON(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// 1. Let jsonString be ? ToString(text).
String* jsonString = argv[0].toString(state);
// 2. Throw a SyntaxError exception if jsonString is the empty String, or
// if either the first or last code unit of jsonString is any of 0x0009 (CHARACTER TABULATION), 0x000A (LINE FEED), 0x000D (CARRIAGE RETURN), or 0x0020 (SPACE).
// 3. Parse StringToCodePoints(jsonString) as a JSON text as specified in ECMA-404.
// Throw a SyntaxError exception if it is not a valid JSON text as defined in that specification,
// or if its outermost value is an object or array as defined in that specification.
auto msg = "input value is not valid JSON text";
if (jsonString->length() == 0) {
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, msg);
}
auto isWrongCodePoint = [](char32_t cp) -> bool {
if (cp == 0x9 || cp == 0xa || cp == 0xd || cp == 0x20) {
return true;
}
return false;
};
if (isWrongCodePoint(jsonString->codePointAt(0).codePoint) || isWrongCodePoint(jsonString->codePointAt(jsonString->length() - 1).codePoint)) {
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, msg);
}
Value jsonParseResult;
try {
jsonParseResult = JSON::parse(state, jsonString, Value());
} catch (const Value& e) {
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, msg);
}
if (jsonParseResult.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, msg);
}
// 4. Let internalSlotsList be « [[IsRawJSON]] ».
// 5. Let obj be OrdinaryObjectCreate(null, internalSlotsList).
// 6. Perform ! CreateDataPropertyOrThrow(obj, "rawJSON", jsonString).
// 7. Perform ! SetIntegrityLevel(obj, frozen).
// 8. Return obj.
return new RawJSONObject(state, jsonString);
}
// https://tc39.es/proposal-json-parse-with-source/#sec-json.israwjson
static Value builtinJSONIsRawJSON(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// 1. If Type(O) is Object and O has an [[IsRawJSON]] internal slot, return true.
if (argv[0].isObject() && argv[0].asObject()->isRawJSONObject()) {
return Value(true);
}
// 2. Return false.
return Value(false);
}
void GlobalObject::initializeJSON(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->json(); }, nullptr);
return self->asGlobalObject()->json();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().JSON), nativeData, Value(Value::EmptyValue));
}
@ -118,15 +69,5 @@ void GlobalObject::installJSON(ExecutionState& state)
m_json->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().stringify),
ObjectPropertyDescriptor(m_jsonStringify,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto rawJSON = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().rawJSON, builtinJSONRawJSON, 1, NativeFunctionInfo::Strict));
m_json->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().rawJSON),
ObjectPropertyDescriptor(rawJSON,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto isRawJSON = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().isRawJSON, builtinJSONIsRawJSON, 1, NativeFunctionInfo::Strict));
m_json->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().isRawJSON),
ObjectPropertyDescriptor(isRawJSON,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}
} // namespace Escargot

View file

@ -22,7 +22,6 @@
#include "runtime/Context.h"
#include "runtime/VMInstance.h"
#include "runtime/MapObject.h"
#include "runtime/ArrayObject.h"
#include "runtime/IteratorObject.h"
#include "runtime/NativeFunctionObject.h"
@ -31,8 +30,7 @@ namespace Escargot {
static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
}
// Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%MapPrototype%", « [[MapData]] »).
@ -40,6 +38,7 @@ static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->mapPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
MapObject* map = new MapObject(state, proto);
// If iterable is not present, or is either undefined or null, return map.
@ -51,52 +50,65 @@ static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_
// Let adder be ? Get(map, "set").
Value adder = map->Object::get(state, ObjectPropertyName(state.context()->staticStrings().set)).value(state, map);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If IsCallable(adder) is false, throw a TypeError exception.
if (!adder.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
}
// Let iteratorRecord be ? GetIterator(iterable).
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
RETURN_VALUE_IF_PENDING_EXCEPTION
while (true) {
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
if (!next.hasValue()) {
return map;
}
{
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!next.hasValue()) {
return map;
}
Value nextItem = IteratorObject::iteratorValue(state, next.value());
if (!nextItem.isObject()) {
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError,
new ASCIIStringFromExternalMemory("Invalid iterator value"));
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
}
Value nextItem = IteratorObject::iteratorValue(state, next.value());
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!nextItem.isObject()) {
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
}
try {
// Let k be Get(nextItem, "0").
// If k is an abrupt completion, return ? IteratorClose(iter, k).
Value k = nextItem.asObject()->getIndexedProperty(state, Value(0)).value(state, nextItem);
if (state.hasPendingException())
goto IfAbrupt;
// Let v be Get(nextItem, "1").
// If v is an abrupt completion, return ? IteratorClose(iter, v).
Value v = nextItem.asObject()->getIndexedProperty(state, Value(1)).value(state, nextItem);
if (state.hasPendingException())
goto IfAbrupt;
// Let status be Call(adder, map, « k.[[Value]], v.[[Value]] »).
Value argv[2] = { k, v };
Object::call(state, adder, map, 2, argv);
} catch (const Value& v) {
// we should save thrown value bdwgc cannot track thrown value
Value exceptionValue = v;
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
if (state.hasPendingException())
goto IfAbrupt;
continue;
}
IfAbrupt : {
ASSERT(state.hasPendingException());
// we should save thrown value bdwgc cannot track thrown value
Value exceptionValue = state.detachPendingException();
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
}
}
return map;
}
#define RESOLVE_THIS_BINDING_TO_MAP(NAME, OBJ, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isMapObject()) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
#define RESOLVE_THIS_BINDING_TO_MAP(NAME, OBJ, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isMapObject()) { \
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
} \
MapObject* NAME = thisValue.asObject()->asMapObject();
static Value builtinMapClear(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -118,18 +130,6 @@ static Value builtinMapGet(ExecutionState& state, Value thisValue, size_t argc,
return M->get(state, argv[0]);
}
static Value builtinMapGetOrInsert(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_MAP(M, Map, getOrInsert);
return M->getOrInsert(state, argv[0], argv[1]);
}
static Value builtinMapGetOrInsertComputed(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_MAP(M, Map, getOrInsertComputed);
return M->getOrInsertComputed(state, argv[0], argv[1]);
}
static Value builtinMapHas(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_MAP(M, Map, has);
@ -153,7 +153,7 @@ static Value builtinMapForEach(ExecutionState& state, Value thisValue, size_t ar
Value callbackfn = argv[0];
// If IsCallable(callbackfn) is false, throw a TypeError exception.
if (!callbackfn.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Map.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Map.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
}
// If thisArg was supplied, let T be thisArg; else let T be undefined.
Value T;
@ -169,6 +169,7 @@ static Value builtinMapForEach(ExecutionState& state, Value thisValue, size_t ar
// Perform ? Call(callbackfn, T, « e.[[Value]], e.[[Key]], M »).
Value argv[3] = { Value(entries[i].second), Value(entries[i].first), Value(M) };
Object::call(state, callbackfn, T, 3, argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
}
@ -202,35 +203,20 @@ static Value builtinMapSizeGetter(ExecutionState& state, Value thisValue, size_t
static Value builtinMapIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!thisValue.isObject() || !thisValue.asObject()->isMapIteratorObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().MapIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().MapIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
}
MapIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asMapIteratorObject();
return iter->next(state);
}
// https://tc39.es/ecma262/multipage/keyed-collections.html#sec-map.groupby
static Value builtinMapGroupBy(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Let groups be ? GroupBy(items, callbackfn, COLLECTION).
auto groups = IteratorObject::groupBy(state, argv[0], argv[1], IteratorObject::GroupByKeyCoercion::Collection);
// Let map be ! Construct(%Map%).
auto map = new MapObject(state);
// For each Record { [[Key]], [[Elements]] } g of groups, do
for (size_t i = 0; i < groups.size(); i++) {
// Let elements be CreateArrayFromList(g.[[Elements]]).
// Let entry be the Record { [[Key]]: g.[[Key]], [[Value]]: elements }.
// Append entry to map.[[MapData]].
map->set(state, groups[i]->key, Value(Object::createArrayFromList(state, groups[i]->elements)));
}
// Return map.
return map;
}
void GlobalObject::initializeMap(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->map(); }, nullptr);
return self->asGlobalObject()->map();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Map), nativeData, Value(Value::EmptyValue));
}
@ -249,10 +235,6 @@ void GlobalObject::installMap(ExecutionState& state)
m_map->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().species), desc);
}
// Map.groupBy
m_map->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groupBy),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().groupBy, builtinMapGroupBy, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapPrototype = new MapObject(state, m_objectPrototype);
m_mapPrototype->setGlobalIntrinsicObject(state, true);
m_mapPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_map, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
@ -266,12 +248,6 @@ void GlobalObject::installMap(ExecutionState& state)
m_mapPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().get),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().get, builtinMapGet, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().getOrInsert),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().getOrInsert, builtinMapGetOrInsert, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().getOrInsertComputed),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().getOrInsertComputed, builtinMapGetOrInsertComputed, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().has),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().has, builtinMapHas, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -24,13 +24,10 @@
#include "runtime/ThreadLocal.h"
#include "runtime/StringObject.h"
#include "runtime/NativeFunctionObject.h"
#include "runtime/IteratorObject.h"
#include "runtime/IEEE754.h"
#include <math.h>
#include "xsum.h"
namespace Escargot {
static Value builtinMathAbs(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -46,8 +43,10 @@ static Value builtinMathMax(ExecutionState& state, Value thisValue, size_t argc,
}
double maxValue = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
for (unsigned i = 1; i < argc; i++) {
double value = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isnan(value))
is_NaN = true;
if (value > maxValue || (!value && !maxValue && !std::signbit(value)))
@ -67,8 +66,10 @@ static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc,
bool hasNaN = false;
double minValue = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
for (unsigned i = 1; i < argc; i++) {
double value = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isnan(value)) {
hasNaN = true;
}
@ -85,6 +86,7 @@ static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc,
static Value builtinMathRound(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
double x = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (x == static_cast<int64_t>(x)) {
return Value(Value::DoubleToIntConvertibleTestNeeds, x);
}
@ -153,7 +155,9 @@ static Value builtinMathAtan(ExecutionState& state, Value thisValue, size_t argc
static Value builtinMathAtan2(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
double y = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
double x = argv[1].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(Value::DoubleToIntConvertibleTestNeeds, ieee754::atan2(y, x));
}
@ -184,6 +188,7 @@ static Value builtinMathTrunc(ExecutionState& state, Value thisValue, size_t arg
static Value builtinMathSign(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
double x = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isnan(x))
return Value(Value::NanInit);
else if (x == 0.0) {
@ -207,7 +212,9 @@ static Value builtinMathSqrt(ExecutionState& state, Value thisValue, size_t argc
static Value builtinMathPow(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
double x = argv[0].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
double y = argv[1].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (UNLIKELY(std::isnan(y)))
return Value(Value::NanInit);
if (UNLIKELY(std::abs(x) == 1 && std::isinf(y)))
@ -323,142 +330,6 @@ static Value builtinMathFround(ExecutionState& state, Value thisValue, size_t ar
return Value(Value::DoubleToIntConvertibleTestNeeds, static_cast<double>(static_cast<float>(x)));
}
// This is extracted from Version 2.2.0 of the half library by Christian Rau.
// See https://sourceforge.net/projects/half/.
// The original copyright and MIT license are reproduced below:
// half - IEEE 754-based half-precision floating-point library.
//
// Copyright (c) 2012-2021 Christian Rau <rauy@users.sourceforge.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/// Type traits for floating-point bits.
template <typename T>
struct bits {
using type = unsigned char;
};
template <typename T>
struct bits<const T> : bits<T> {};
template <typename T>
struct bits<volatile T> : bits<T> {};
template <typename T>
struct bits<const volatile T> : bits<T> {};
/// Unsigned integer of (at least) 64 bits width.
template <>
struct bits<double> {
using type = std::uint_least64_t;
};
/// Fastest unsigned integer of (at least) 32 bits width.
using uint32 = std::uint_fast32_t;
/// Half-precision overflow.
/// \param sign half-precision value with sign bit only
/// \return rounded overflowing half-precision value
constexpr unsigned int overflow(unsigned int sign = 0) { return sign | 0x7C00; }
/// Half-precision underflow.
/// \param sign half-precision value with sign bit only
/// \return rounded underflowing half-precision value
constexpr unsigned int underflow(unsigned int sign = 0) { return sign; }
/// Round half-precision number.
/// \param value finite half-precision number to round
/// \param g guard bit (most significant discarded bit)
/// \param s sticky bit (or of all but the most significant discarded bits)
/// \return rounded half-precision value
constexpr unsigned int rounded(unsigned int value, int g, int s)
{
return value + (g & (s | value));
}
/// Convert IEEE double-precision to half-precision.
/// \param value double-precision value to convert
/// \return rounded half-precision value
inline unsigned int float2half_impl(double value)
{
bits<double>::type dbits;
std::memcpy(&dbits, &value, sizeof(double));
uint32 hi = dbits >> 32, lo = dbits & 0xFFFFFFFF;
unsigned int sign = (hi >> 16) & 0x8000;
hi &= 0x7FFFFFFF;
if (hi >= 0x7FF00000)
return sign | 0x7C00 | ((dbits & 0xFFFFFFFFFFFFF) ? (0x200 | ((hi >> 10) & 0x3FF)) : 0);
if (hi >= 0x40F00000)
return overflow(sign);
if (hi >= 0x3F100000)
return rounded(sign | (((hi >> 20) - 1008) << 10) | ((hi >> 10) & 0x3FF),
(hi >> 9) & 1, ((hi & 0x1FF) | lo) != 0);
if (hi >= 0x3E600000) {
int i = 1018 - (hi >> 20);
hi = (hi & 0xFFFFF) | 0x100000;
return rounded(sign | (hi >> (i + 1)), (hi >> i) & 1,
((hi & ((static_cast<uint32>(1) << i) - 1)) | lo) != 0);
}
if ((hi | lo) != 0)
return underflow(sign);
return sign;
}
/// Convert half-precision to IEEE double-precision.
/// \param value half-precision value to convert
/// \return double-precision value
inline double half2float_impl(unsigned int value)
{
uint32 hi = static_cast<uint32>(value & 0x8000) << 16;
unsigned int abs = value & 0x7FFF;
if (abs) {
hi |= 0x3F000000 << static_cast<unsigned>(abs >= 0x7C00);
for (; abs < 0x400; abs <<= 1, hi -= 0x100000)
;
hi += static_cast<uint32>(abs) << 10;
}
bits<double>::type dbits = static_cast<bits<double>::type>(hi) << 32;
double out;
std::memcpy(&out, &dbits, sizeof(double));
return out;
}
// End of the half library extraction.
// \brief Conversion from float/double to half round number.
// \details For the specification, see https://tc39.es/proposal-float16array/#sec-function-properties-of-the-math-object.
// \author Anwar Fuadi
// \date 2025-present
static auto builtinMathF16round(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) -> Value
{
// 1. Let n be ? ToNumber(x).
auto x = double{ argv[0].toNumber(state) };
// 2. If n is NaN, return NaN.
// 3. If n is one of +0𝔽, -0𝔽, +∞𝔽, or -∞𝔽, return n.
// 4. Let n16 be the result of converting n to IEEE 754-2019 binary16 format using roundTiesToEven mode.
auto f16 = float2half_impl(x);
x = half2float_impl(f16);
// 5. Let n64 be the result of converting n16 to IEEE 754-2019 binary64 format.
// 6. Return the ECMAScript Number value corresponding to n64.
return Value(Value::DoubleToIntConvertibleTestNeeds, x);
}
static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
double maxValue = 0;
@ -466,6 +337,7 @@ static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t arg
bool has_inf = false;
for (unsigned i = 0; i < argc; i++) {
double value = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isinf(value)) {
has_inf = true;
} else if (std::isnan(value)) {
@ -490,6 +362,7 @@ static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t arg
double compensation = 0;
for (unsigned i = 0; i < argc; i++) {
double value = argv[i].toNumber(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
double scaledArgument = value / maxValue;
double summand = scaledArgument * scaledArgument - compensation;
double preliminary = sum + summand;
@ -548,133 +421,14 @@ static Value builtinMathExpm1(ExecutionState& state, Value thisValue, size_t arg
return Value(Value::DoubleToIntConvertibleTestNeeds, ieee754::expm1(x));
}
enum class SumPreciseState {
MinusZero,
NotANumber,
MinusInfinity,
PlusInfinity,
Finite
};
// https://tc39.es/proposal-math-sum/#sec-math.sumprecise
static Value builtinMathSumPrecise(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
const Value& items = argv[0];
// 1. Perform ? RequireObjectCoercible(items).
if (items.isUndefinedOrNull()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "sumPrecise called on undefined or null");
}
xsum_small_accumulator sacc;
xsum_small_init(&sacc);
// 2. Let iteratorRecord be ? GetIterator(items, sync).
auto iteratorRecord = IteratorObject::getIterator(state, items, true);
// 3. Let state be minus-zero.
SumPreciseState sumPreciseState = SumPreciseState::MinusZero;
// 4. Let sum be 0.
// 5. Let count be 0.
// 6. Let next be not-started.
uint64_t count = 0;
// 7. Repeat, while next is not done,
while (true) {
// a. Set next to ? IteratorStepValue(iteratorRecord).
auto next = IteratorObject::iteratorStepValue(state, iteratorRecord);
// b. If next is not done, then
if (next) {
// i. Set count to count + 1.
count++;
// ii. If count ≥ 2**53, then
if (count >= (1LL << 53LL)) {
// 1. Let error be ThrowCompletion(a newly created RangeError object).
Value error = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIStringFromExternalMemory("Too many result on sumPrecise function"));
// 2. Return ? IteratorClose(iteratorRecord, error).
IteratorObject::iteratorClose(state, iteratorRecord, error, true);
ASSERT_NOT_REACHED();
}
// iii. NOTE: The above case is not expected to be reached in practice and is included only so that implementations may rely on inputs being "reasonably sized" without violating this specification.
// iv. If next is not a Number, then
if (!next.value().isNumber()) {
// 1. Let error be ThrowCompletion(a newly created TypeError object).
Value error = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIStringFromExternalMemory("sumPrecise function needs number value"));
// 2. Return ? IteratorClose(iteratorRecord, error).
IteratorObject::iteratorClose(state, iteratorRecord, error, true);
ASSERT_NOT_REACHED();
}
// v. Let n be next.
double n = next.value().asNumber();
// vi. If state is not not-a-number, then
if (sumPreciseState != SumPreciseState::NotANumber) {
// 1. If n is NaN, then
if (std::isnan(n)) {
// a. Set state to not-a-number.
sumPreciseState = SumPreciseState::NotANumber;
} else if (std::isinf(n) && std::signbit(n) == 0) {
// 2. Else if n is +∞𝔽, then
// a. If state is minus-infinity, set state to not-a-number.
if (sumPreciseState == SumPreciseState::MinusInfinity) {
sumPreciseState = SumPreciseState::NotANumber;
} else {
// b. Else, set state to plus-infinity.
sumPreciseState = SumPreciseState::PlusInfinity;
}
} else if (std::isinf(n) && std::signbit(n) == 1) {
// 3. Else if n is -∞𝔽, then
// a. If state is plus-infinity, set state to not-a-number.
if (sumPreciseState == SumPreciseState::PlusInfinity) {
sumPreciseState = SumPreciseState::NotANumber;
} else {
// b. Else, set state to minus-infinity.
sumPreciseState = SumPreciseState::MinusInfinity;
}
} else if (!(n == 0 && std::signbit(n)) && (sumPreciseState == SumPreciseState::MinusZero || sumPreciseState == SumPreciseState::Finite)) {
// 4. Else if n is not -0𝔽 and state is either minus-zero or finite, then
// a. Set state to finite.
sumPreciseState = SumPreciseState::Finite;
// b. Set sum to sum + (n).
xsum_small_add1(&sacc, n);
}
}
} else {
break;
}
}
// 8. If state is not-a-number, return NaN.
// 9. If state is plus-infinity, return +∞𝔽.
// 10. If state is minus-infinity, return -∞𝔽.
// 11. If state is minus-zero, return -0𝔽.
// 12. Return 𝔽(sum).
double result = 0;
switch (sumPreciseState) {
case SumPreciseState::NotANumber:
result = std::numeric_limits<double>::quiet_NaN();
break;
case SumPreciseState::PlusInfinity:
result = std::numeric_limits<double>::infinity();
break;
case SumPreciseState::MinusInfinity:
result = -std::numeric_limits<double>::infinity();
break;
case SumPreciseState::MinusZero:
result = -0.0;
break;
case SumPreciseState::Finite:
result = xsum_small_round(&sacc);
break;
default:
ASSERT_NOT_REACHED();
}
return Value(Value::DoubleToIntConvertibleTestNeeds, result);
}
void GlobalObject::initializeMath(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->math(); }, nullptr);
return self->asGlobalObject()->math();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Math), nativeData, Value(Value::EmptyValue));
}
@ -811,13 +565,6 @@ void GlobalObject::installMath(ExecutionState& state)
m_math->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().trunc),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().trunc, builtinMathTrunc, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_math->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().sumPrecise),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().sumPrecise, builtinMathSumPrecise, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_math->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().f16round),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().f16round, builtinMathF16round, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Math),
ObjectPropertyDescriptor(m_math, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}

View file

@ -82,6 +82,7 @@ static Value builtinNumberConstructor(ExecutionState& state, Value thisValue, si
} else {
num = argv[0].toNumber(state);
}
RETURN_VALUE_IF_PENDING_EXCEPTION
}
if (!newTarget.hasValue()) {
@ -90,6 +91,7 @@ static Value builtinNumberConstructor(ExecutionState& state, Value thisValue, si
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->numberPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
NumberObject* numObj = new NumberObject(state, proto, num);
return numObj;
}
@ -104,13 +106,14 @@ static Value builtinNumberToFixed(ExecutionState& state, Value thisValue, size_t
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
} else {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
Value fractionDigits = argv[0];
int digit = fractionDigits.toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (digit < 0 || digit > 100) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_RangeError);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_RangeError);
}
if (std::isnan(number)) {
@ -145,11 +148,12 @@ static Value builtinNumberToExponential(ExecutionState& state, Value thisValue,
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
} else {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
Value fractionDigits = argv[0];
int digit = fractionDigits.toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isnan(number)) { // 3
return state.context()->staticStrings().NaN.string();
@ -164,7 +168,7 @@ static Value builtinNumberToExponential(ExecutionState& state, Value thisValue,
}
if (digit < 0 || digit > 100) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_RangeError);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_RangeError);
}
char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
@ -187,7 +191,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
} else {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
Value precision = argv[0];
@ -196,6 +200,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
}
int p = precision.toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (std::isnan(number)) {
return state.context()->staticStrings().NaN.string();
@ -210,7 +215,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
}
if (p < 1 || p > 100) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_RangeError);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_RangeError);
}
char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
@ -229,14 +234,15 @@ static Value builtinNumberToString(ExecutionState& state, Value thisValue, size_
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
} else {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
double radix = 10;
if (argc > 0 && !argv[0].isUndefined()) {
radix = argv[0].toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (radix < 2 || radix > 36) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
}
}
if (std::isnan(number) || std::isinf(number)) {
@ -251,28 +257,26 @@ static Value builtinNumberToString(ExecutionState& state, Value thisValue, size_
bool minusFlag = (number < 0) ? 1 : 0;
number = (number < 0) ? (-1 * number) : number;
char buffer[256];
size_t len;
if (minusFlag) {
buffer[0] = '-';
len = itoa(static_cast<int64_t>(number), &buffer[1], radix);
len += 1;
itoa(static_cast<int64_t>(number), &buffer[1], radix);
} else {
len = itoa(static_cast<int64_t>(number), buffer, radix);
itoa(static_cast<int64_t>(number), buffer, radix);
}
return String::fromASCII(buffer, len);
return String::fromASCII(buffer, strlen(buffer));
} else {
ASSERT(Value(Value::DoubleToIntConvertibleTestNeeds, number).isDouble());
NumberObject::RadixBuffer s;
const char* str = NumberObject::toStringWithRadix(state, s, number, radix);
return String::fromASCII(str, strnlen(str, sizeof(NumberObject::RadixBuffer)));
return String::fromASCII(str, strlen(str));
}
}
static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Object* thisObject = thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Number, toLocaleString);
if (!thisObject->isNumberObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
#if defined(ENABLE_ICU) && defined(ENABLE_INTL_NUMBERFORMAT)
@ -285,7 +289,7 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
} else if (thisValue.isObject() && thisValue.asObject()->isNumberObject()) {
x = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
} else {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
auto result = IntlNumberFormat::format(state, numberFormat, x);
@ -295,14 +299,13 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
ObjectGetResult toStrFuncGetResult = thisObject->get(state, ObjectPropertyName(state.context()->staticStrings().toString));
if (toStrFuncGetResult.hasValue()) {
Value toStrFunc = toStrFuncGetResult.value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (toStrFunc.isCallable()) {
// toLocaleString() ignores the first argument, unlike toString()
return Object::call(state, toStrFunc, thisObject, 0, argv);
}
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
RELEASE_ASSERT_NOT_REACHED();
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
#endif
}
@ -313,9 +316,7 @@ static Value builtinNumberValueOf(ExecutionState& state, Value thisValue, size_t
} else if (thisValue.isObject() && thisValue.asObject()->isNumberObject()) {
return Value(Value::DoubleToIntConvertibleTestNeeds, thisValue.asPointerValue()->asNumberObject()->primitiveValue());
}
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
RELEASE_ASSERT_NOT_REACHED();
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
}
static Value builtinNumberIsFinite(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -343,6 +344,7 @@ static Value builtinNumberIsInteger(ExecutionState& state, Value thisValue, size
}
double integer = argv[0].toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (number != integer) {
return Value(Value::False);
}
@ -374,6 +376,7 @@ static Value builtinNumberIsSafeInteger(ExecutionState& state, Value thisValue,
}
double integer = argv[0].toInteger(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (number != integer) {
return Value(Value::False);
}
@ -386,9 +389,12 @@ static Value builtinNumberIsSafeInteger(ExecutionState& state, Value thisValue,
void GlobalObject::initializeNumber(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->number(); }, nullptr);
return self->asGlobalObject()->number();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Number), nativeData, Value(Value::EmptyValue));
}

View file

@ -31,19 +31,23 @@ typedef VectorWithInlineStorage<48, std::pair<ObjectPropertyName, ObjectStructur
static Value builtinObject__proto__Getter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
return thisValue.toObject(state)->getPrototype(state);
Object* obj = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return obj->getPrototype(state);
}
static Value builtinObject__proto__Setter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Value value = argv[0];
Object* thisObject = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Setting __proto__ to a non-object, non-null value is ignored
if (!value.isObject() && !value.isNull()) {
return Value();
}
if (!thisObject->setPrototype(state, value)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
RETURN_VALUE_IF_PENDING_EXCEPTION
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
}
return Value();
}
@ -56,6 +60,7 @@ static Value builtinObjectConstructor(ExecutionState& state, Value thisValue, si
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->objectPrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
return new Object(state, proto);
}
@ -71,7 +76,8 @@ static Value builtinObjectConstructor(ExecutionState& state, Value thisValue, si
static Value builtinObjectValueOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
return thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(ret, Object, valueOf);
return ret;
}
static Value builtinObjectPreventExtensions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -81,7 +87,8 @@ static Value builtinObjectPreventExtensions(ExecutionState& state, Value thisVal
}
Object* o = argv[0].asObject();
if (!o->preventExtensions(state)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().preventExtensions.string(), "PreventExtensions is false");
RETURN_VALUE_IF_PENDING_EXCEPTION
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().preventExtensions.string(), "PreventExtensions is false");
}
return o;
}
@ -97,11 +104,14 @@ static Value builtinObjectToString(ExecutionState& state, Value thisValue, size_
}
Object* thisObject = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// check isArray first
bool isArray = thisObject->isArray(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value toStringTag = thisObject->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag)).value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (toStringTag.isString()) {
String* tag = toStringTag.asString();
auto bad = tag->bufferAccessData();
@ -158,13 +168,18 @@ static Value builtinObjectToString(ExecutionState& state, Value thisValue, size_
static Value builtinObjectHasOwn(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Object* obj = argv[0].toObject(state);
return Value(obj->hasOwnProperty(state, ObjectPropertyName(state, argv[1])));
RETURN_VALUE_IF_PENDING_EXCEPTION
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(obj->hasOwnProperty(state, key));
}
static Value builtinObjectHasOwnProperty(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
ObjectPropertyName key(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
Object* obj = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(obj->hasOwnProperty(state, key));
}
@ -173,12 +188,13 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
const StaticStrings* strings = &state.context()->staticStrings();
if (!object.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Object.string(), false, strings->defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Object.string(), false, strings->defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
}
Object* O = object.asObject();
// Let props be ? ToObject(Properties).
Object* props = properties.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let keys be ? props.[[OwnPropertyKeys]]().
Object::OwnPropertyKeyVector keys = props->ownPropertyKeys(state);
@ -188,17 +204,20 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
for (size_t i = 0; i < keys.size(); i++) {
// Let propDesc be ? props.[[GetOwnProperty]](nextKey).
ObjectPropertyName nextKey(state, keys[i]);
RETURN_VALUE_IF_PENDING_EXCEPTION
ObjectGetResult propDesc = props->getOwnProperty(state, nextKey);
// If propDesc is not undefined and propDesc.[[Enumerable]] is true, then
if (propDesc.hasValue() && propDesc.isEnumerable()) {
// Let descObj be ? Get(props, nextKey).
Value descVal = propDesc.value(state, props);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!descVal.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_DescriptorNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_DescriptorNotObject);
}
// Let desc be ? ToPropertyDescriptor(descObj).
ObjectPropertyDescriptor desc(state, descVal.asObject());
RETURN_VALUE_IF_PENDING_EXCEPTION
// Append the pair (a two element List) consisting of nextKey and desc to the end of descriptors.
descriptors.push_back(std::make_pair(nextKey, desc));
}
@ -210,6 +229,7 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
// Let desc be the second element of pair.
// Perform ? DefinePropertyOrThrow(O, P, desc).
O->defineOwnPropertyThrowsException(state, it.first, it.second);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
return O;
@ -218,13 +238,14 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
static Value builtinObjectCreate(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!argv[0].isObject() && !argv[0].isNull())
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().create.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObjectAndNotNull);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().create.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObjectAndNotNull);
Object* obj;
if (argv[0].isNull()) {
obj = new Object(state, Object::PrototypeIsNull);
} else {
obj = new Object(state);
obj->setPrototype(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
if (!argv[1].isUndefined())
@ -242,21 +263,24 @@ static Value builtinObjectDefineProperty(ExecutionState& state, Value thisValue,
// Object.defineProperty ( O, P, Attributes )
// If Type(O) is not Object, throw a TypeError exception.
if (!argv[0].isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
}
Object* O = argv[0].asObject();
// Let key be ToPropertyKey(P).
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let desc be ToPropertyDescriptor(Attributes).
if (!argv[2].isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Property description must be an object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Property description must be an object");
}
ObjectPropertyDescriptor desc(state, argv[2].asObject());
RETURN_VALUE_IF_PENDING_EXCEPTION
O->defineOwnPropertyThrowsException(state, key, desc);
RETURN_VALUE_IF_PENDING_EXCEPTION
return O;
}
@ -270,12 +294,13 @@ static Value builtinObjectIsPrototypeOf(ExecutionState& state, Value thisValue,
Value V = argv[0];
// Let O be the result of calling ToObject passing the this value as the argument.
Object* O = thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, isPrototypeOf);
// Repeat
while (true) {
// Let V be the value of the [[Prototype]] internal property of V.
V = V.toObject(state)->getPrototype(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// if V is null, return false
if (!V.isObject())
return Value(false);
@ -290,9 +315,10 @@ static Value builtinObjectPropertyIsEnumerable(ExecutionState& state, Value this
{
// Let P be toPropertyKey(V).
ObjectPropertyName P(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let O be the result of calling ToObject passing the this value as the argument.
Object* O = thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, propertyIsEnumerable);
// Let desc be the result of calling the [[GetOwnProperty]] internal method of O with argument name.
ObjectGetResult desc = O->getOwnProperty(state, P);
@ -310,14 +336,17 @@ static Value builtinObjectToLocaleString(ExecutionState& state, Value thisValue,
// https://www.ecma-international.org/ecma-262/#sec-object.prototype.tolocalestring
// Let O be the this value.
// Return ? Invoke(O, "toString").
Object* O = thisValue.toObject(state);
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, toLocaleString);
Value toString = O->get(state, ObjectPropertyName(state.context()->staticStrings().toString)).value(state, thisValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Object::call(state, toString, thisValue, 0, nullptr);
}
static Value builtinObjectGetPrototypeOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
return argv[0].toObject(state)->getPrototype(state);
Object* obj = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return obj->getPrototype(state);
}
static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -330,13 +359,13 @@ static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue,
// 1. Let O be RequireObjectCoercible(O).
// 2. ReturnIfAbrupt(O).
if (object.isUndefinedOrNull()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
return Value();
}
// 3. If Type(proto) is neither Object nor Null, throw a TypeError exception.
if (!proto.isObject() && !proto.isNull()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
return Value();
}
@ -347,10 +376,13 @@ static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue,
// 5. Let status be O.[[SetPrototypeOf]](proto).
Object* obj = object.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
bool status = obj->setPrototype(state, proto);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 7. If status is false, throw a TypeError exception.
if (!obj->setPrototype(state, proto)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
if (!status) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
return Value();
}
@ -369,7 +401,8 @@ static Value builtinObjectFreeze(ExecutionState& state, Value thisValue, size_t
// Let status be ? SetIntegrityLevel(O, frozen).
// If status is false, throw a TypeError exception.
if (!Object::setIntegrityLevel(state, O, false)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().freeze.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
RETURN_VALUE_IF_PENDING_EXCEPTION
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().freeze.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
// Return O.
@ -379,42 +412,55 @@ static Value builtinObjectFreeze(ExecutionState& state, Value thisValue, size_t
static Value builtinObjectFromEntries(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (argv[0].isUndefinedOrNull()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().fromEntries.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().fromEntries.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
}
Value iterable = argv[0];
Object* obj = new Object(state);
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
RETURN_VALUE_IF_PENDING_EXCEPTION
while (true) {
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
if (!next.hasValue()) {
return obj;
}
{
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!next.hasValue()) {
return obj;
}
Value nextItem = IteratorObject::iteratorValue(state, next.value());
if (!nextItem.isObject()) {
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError,
new ASCIIStringFromExternalMemory("Invalid iterator value"));
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
}
Value nextItem = IteratorObject::iteratorValue(state, next.value());
RETURN_VALUE_IF_PENDING_EXCEPTION
if (!nextItem.isObject()) {
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
}
try {
// Let k be Get(nextItem, "0").
// If k is an abrupt completion, return ? IteratorClose(iter, k).
Value k = nextItem.asObject()->getIndexedProperty(state, Value(0)).value(state, nextItem);
if (state.hasPendingException())
goto IfAbrupt;
// Let v be Get(nextItem, "1").
// If v is an abrupt completion, return ? IteratorClose(iter, v).
Value v = nextItem.asObject()->getIndexedProperty(state, Value(1)).value(state, nextItem);
if (state.hasPendingException())
goto IfAbrupt;
ObjectPropertyName key(state, k);
if (state.hasPendingException())
goto IfAbrupt;
obj->defineOwnPropertyThrowsException(state, key,
ObjectPropertyDescriptor(v, ObjectPropertyDescriptor::AllPresent));
} catch (const Value& v) {
// we should save thrown value bdwgc cannot track thrown value
Value exceptionValue = v;
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
if (state.hasPendingException())
goto IfAbrupt;
continue;
}
IfAbrupt : {
ASSERT(state.hasPendingException());
Value exceptionValue = state.detachPendingException();
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
}
}
return obj;
@ -425,23 +471,29 @@ static Value builtinObjectGetOwnPropertyDescriptor(ExecutionState& state, Value
{
// Let obj be ToObject(O).
Object* O = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let desc be ? obj.[[GetOwnProperty]](key).
// Return FromPropertyDescriptor(desc).
return O->getOwnPropertyDescriptor(state, ObjectPropertyName(state, argv[1]));
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
return O->getOwnPropertyDescriptor(state, key);
}
// https://262.ecma-international.org/#sec-object.getownpropertydescriptors
static Value builtinObjectGetOwnPropertyDescriptors(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
Object* obj = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
auto ownKeys = obj->ownPropertyKeys(state);
Object* descriptors = new Object(state);
for (uint64_t i = 0; i < ownKeys.size(); i++) {
Value descriptor = obj->getOwnPropertyDescriptor(state, ObjectPropertyName(state, ownKeys[i]));
ObjectPropertyName key = ObjectPropertyName(state, ownKeys[i]);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value descriptor = obj->getOwnPropertyDescriptor(state, key);
if (!descriptor.isUndefined()) {
descriptors->defineOwnProperty(state, ObjectPropertyName(state, ownKeys[i]), ObjectPropertyDescriptor(descriptor, ObjectPropertyDescriptor::AllPresent));
descriptors->defineOwnProperty(state, key, ObjectPropertyDescriptor(descriptor, ObjectPropertyDescriptor::AllPresent));
}
}
return descriptors;
@ -489,6 +541,7 @@ static Value builtinObjectGetOwnPropertyNames(ExecutionState& state, Value thisV
{
// https://www.ecma-international.org/ecma-262/6.0/#sec-object.getownpropertynames
Object* O = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return getOwnPropertyKeys(state, O, GetOwnPropertyKeysType::String);
}
@ -496,6 +549,7 @@ static Value builtinObjectGetOwnPropertySymbols(ExecutionState& state, Value thi
{
// https://www.ecma-international.org/ecma-262/6.0/#sec-object.getownpropertysymbols
Object* O = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return getOwnPropertyKeys(state, O, GetOwnPropertyKeysType::Symbol);
}
@ -538,7 +592,8 @@ static Value builtinObjectSeal(ExecutionState& state, Value thisValue, size_t ar
// Let status be ? SetIntegrityLevel(O, sealed).
// If status is false, throw a TypeError exception.
if (!Object::setIntegrityLevel(state, O, true)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().seal.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
RETURN_VALUE_IF_PENDING_EXCEPTION
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().seal.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
}
// Return O.
@ -550,6 +605,7 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
// Object.assign ( target, ...sources )
// Let to be ? ToObject(target).
Object* to = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If only one argument was passed, return to.
if (argc == 1) {
return to;
@ -564,6 +620,7 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
if (!nextSource.isUndefinedOrNull()) {
// Let from be ! ToObject(nextSource).
from = nextSource.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let keys be ? from.[[OwnPropertyKeys]]().
keys = from->ownPropertyKeys(state);
}
@ -571,19 +628,23 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
// For each element nextKey of keys in List order, do
for (size_t i = 0; i < keys.size(); i++) {
Value nextKey = keys[i];
ObjectPropertyName key = ObjectPropertyName(state, nextKey);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let desc be ? from.[[GetOwnProperty]](nextKey).
auto desc = from->getOwnProperty(state, ObjectPropertyName(state, nextKey));
auto desc = from->getOwnProperty(state, key);
// If desc is not undefined and desc.[[Enumerable]] is true, then
if (desc.hasValue() && desc.isEnumerable()) {
// Let propValue be ? Get(from, nextKey).
Value propValue;
if (from->isProxyObject()) {
propValue = from->get(state, ObjectPropertyName(state, Value(nextKey))).value(state, from);
propValue = from->get(state, key).value(state, from);
} else {
propValue = desc.value(state, from);
}
RETURN_VALUE_IF_PENDING_EXCEPTION
// Perform ? Set(to, nextKey, propValue, true).
to->setThrowsException(state, ObjectPropertyName(state, nextKey), propValue, to);
to->setThrowsException(state, key, propValue, to);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
}
}
@ -604,6 +665,7 @@ static Value builtinObjectKeys(ExecutionState& state, Value thisValue, size_t ar
// Let obj be ? ToObject(O).
Object* obj = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let nameList be ? EnumerableOwnProperties(obj, "key").
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::Key);
// Return CreateArrayFromList(nameList).
@ -616,6 +678,7 @@ static Value builtinObjectValues(ExecutionState& state, Value thisValue, size_t
// Let obj be ? ToObject(O).
Object* obj = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let nameList be ? EnumerableOwnProperties(obj, "value").
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::Value);
// Return CreateArrayFromList(nameList).
@ -628,6 +691,7 @@ static Value builtinObjectEntries(ExecutionState& state, Value thisValue, size_t
// Let obj be ? ToObject(O).
Object* obj = argv[0].toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let nameList be ? EnumerableOwnProperties(obj, "key+value").
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::KeyAndValue);
// Return CreateArrayFromList(nameList).
@ -639,21 +703,24 @@ static Value builtinDefineGetter(ExecutionState& state, Value thisValue, size_t
{
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If IsCallable(getter) is false, throw a TypeError exception.
if (!argv[1].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::emptyString(), true, state.context()->staticStrings().__defineGetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineGetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
}
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
ObjectPropertyDescriptor desc(JSGetterSetter(argv[1].asObject(), Value(Value::EmptyValue)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Perform ? DefinePropertyOrThrow(O, key, desc).
#if defined(ENABLE_V8_LIKE_DEFINE_LOOKUP_GETTER_SETTER)
O->defineOwnProperty(state, key, desc);
#else
O->defineOwnPropertyThrowsException(state, key, desc);
RETURN_VALUE_IF_PENDING_EXCEPTION
#endif
// Return undefined.
@ -665,21 +732,24 @@ static Value builtinDefineSetter(ExecutionState& state, Value thisValue, size_t
{
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If IsCallable(getter) is false, throw a TypeError exception.
if (!argv[1].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::emptyString(), true, state.context()->staticStrings().__defineSetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineSetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
}
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
ObjectPropertyDescriptor desc(JSGetterSetter(Value(Value::EmptyValue), argv[1].asObject()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Perform ? DefinePropertyOrThrow(O, key, desc).
#if defined(ENABLE_V8_LIKE_DEFINE_LOOKUP_GETTER_SETTER)
O->defineOwnProperty(state, key, desc);
#else
O->defineOwnPropertyThrowsException(state, key, desc);
RETURN_VALUE_IF_PENDING_EXCEPTION
#endif
// Return undefined.
@ -691,8 +761,10 @@ static Value builtinLookupGetter(ExecutionState& state, Value thisValue, size_t
{
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Repeat,
while (O) {
@ -720,8 +792,10 @@ static Value builtinLookupSetter(ExecutionState& state, Value thisValue, size_t
{
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Repeat,
while (O) {
@ -744,24 +818,6 @@ static Value builtinLookupSetter(ExecutionState& state, Value thisValue, size_t
return Value();
}
// https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.groupby
static Value builtinObjectGroupBy(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Let groups be ? GroupBy(items, callbackfn, PROPERTY).
auto groups = IteratorObject::groupBy(state, argv[0], argv[1], IteratorObject::GroupByKeyCoercion::Property);
// Let obj be OrdinaryObjectCreate(null).
auto obj = new Object(state, Object::PrototypeIsNull);
// For each Record { [[Key]], [[Elements]] } g of groups, do
for (size_t i = 0; i < groups.size(); i++) {
// Let elements be CreateArrayFromList(g.[[Elements]]).
// Perform ! CreateDataPropertyOrThrow(obj, g.[[Key]], elements).
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, groups[i]->key),
ObjectPropertyDescriptor(Object::createArrayFromList(state, groups[i]->elements), ObjectPropertyDescriptor::AllPresent));
}
// Return obj.
return obj;
}
void GlobalObject::initializeObject(ExecutionState& state)
{
// Object should be installed at the start time
@ -896,10 +952,6 @@ void GlobalObject::installObject(ExecutionState& state)
m_object->directDefineOwnProperty(state, ObjectPropertyName(strings.hasOwn),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings.hasOwn, builtinObjectHasOwn, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// Object.groupBy
m_object->directDefineOwnProperty(state, ObjectPropertyName(strings.groupBy),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings.groupBy, builtinObjectGroupBy, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $19.1.3.2 Object.prototype.hasOwnProperty(V)
m_objectPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings.hasOwnProperty),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings.hasOwnProperty, builtinObjectHasOwnProperty, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -36,19 +36,19 @@ static Value builtinPromiseConstructor(ExecutionState& state, Value thisValue, s
{
auto strings = &state.context()->staticStrings();
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString(), "%s: Promise constructor should be called with new Promise()");
return Value();
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise constructor should be called with new Promise()");
}
Value executor = argv[0];
if (!executor.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString(), "%s: Promise executor is not a function object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise executor is not a function object");
}
// Let promise be ? OrdinaryCreateFromConstructor(NewTarget, "%PromisePrototype%", « [[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]], [[PromiseIsHandled]] »).
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
return constructorRealm->globalObject()->promisePrototype();
});
RETURN_VALUE_IF_PENDING_EXCEPTION
PromiseObject* promise = new PromiseObject(state, proto);
PromiseReaction::Capability capability = promise->createResolvingFunctions(state);
@ -60,12 +60,14 @@ static Value builtinPromiseConstructor(ExecutionState& state, Value thisValue, s
state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Init, promise, (argc > 1) ? argv[1] : Value());
}
try {
{
Value arguments[] = { capability.m_resolveFunction, capability.m_rejectFunction };
Object::call(state, executor, Value(), 2, arguments);
} catch (const Value& v) {
Value thrownValue = v;
Object::call(state, capability.m_rejectFunction, Value(), 1, &thrownValue);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
Object::call(state, capability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
}
return promise;
@ -77,9 +79,10 @@ static Value getPromiseResolve(ExecutionState& state, Object* promiseConstructor
// Assert: IsConstructor(promiseConstructor) is true.
// Let promiseResolve be ? Get(promiseConstructor, "resolve").
auto promiseResolve = promiseConstructor->get(state, state.context()->staticStrings().resolve).value(state, promiseConstructor);
RETURN_VALUE_IF_PENDING_EXCEPTION
// If IsCallable(promiseResolve) is false, throw a TypeError exception.
if (!promiseResolve.isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Promise resolve is not callable");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Promise resolve is not callable");
}
// Return promiseResolve.
return promiseResolve;
@ -93,141 +96,147 @@ static Value builtinPromiseAll(ExecutionState& state, Value thisValue, size_t ar
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
if (!thisValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
}
Object* C = thisValue.asObject();
// Let promiseCapability be NewPromiseCapability(C).
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let promiseResolve be GetPromiseResolve(C).
Value promiseResolve;
try {
promiseResolve = getPromiseResolve(state, C);
} catch (const Value& v) {
Value thrownValue = v;
Value promiseResolve = getPromiseResolve(state, C);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let iteratorRecord be GetIterator(iterable).
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
IteratorRecord* iteratorRecord;
try {
iteratorRecord = IteratorObject::getIterator(state, argv[0]);
} catch (const Value& v) {
Value thrownValue = v;
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, argv[0]);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability).
Value result;
try {
// Let values be a new empty List.
ValueVector* values = new ValueVector();
// Let remainingElementsCount be a new Record { [[value]]: 1 }.
size_t* remainingElementsCount = new (PointerFreeGC) size_t(1);
// Let values be a new empty List.
ValueVector* values = new ValueVector();
// Let remainingElementsCount be a new Record { [[value]]: 1 }.
size_t* remainingElementsCount = new (PointerFreeGC) size_t(1);
// Let index be 0.
int64_t index = 0;
// Let index be 0.
int64_t index = 0;
// Repeat
while (true) {
// Let next be IteratorStep(iteratorRecord).
Optional<Object*> next;
try {
next = IteratorObject::iteratorStep(state, iteratorRecord);
} catch (const Value& e) {
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(next).
state.throwException(e);
}
// If next is false,
if (!next.hasValue()) {
// set iteratorRecord.[[done]] to true.
iteratorRecord->m_done = true;
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] 1.
*remainingElementsCount = *remainingElementsCount - 1;
// If remainingElementsCount.[[value]] is 0,
if (*remainingElementsCount == 0) {
// Let valuesArray be CreateArrayFromList(values).
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
Value argv = Object::createArrayFromList(state, *values);
Value resolveResult = Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &argv);
}
// Return resultCapability.[[Promise]].
result = promiseCapability.m_promise;
break;
}
// Let nextValue be IteratorValue(next).
Value nextValue;
try {
nextValue = IteratorObject::iteratorValue(state, next.value());
} catch (const Value& e) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(nextValue).
state.throwException(e);
}
// Append undefined to values.
values->pushBack(Value());
// Let nextPromise be Invoke(constructor, "resolve", « nextValue »).
Value nextPromise = Object::call(state, promiseResolve, C, 1, &nextValue);
// Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
ExtendedNativeFunctionObject* resolveElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAllResolveElementFunction, 1, NativeFunctionInfo::Strict));
// Set the [[AlreadyCalled]] internal slot of resolveElement to a new Record {[[value]]: false }.
// Set the [[Index]] internal slot of resolveElement to index.
// Set the [[Values]] internal slot of resolveElement to values.
// Set the [[Capabilities]] internal slot of resolveElement to resultCapability.
// Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount.
bool* alreadyCalled = new (PointerFreeGC) bool(false);
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::AlreadyCalled, alreadyCalled);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Index, Value(index));
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::Values, values);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Resolve, promiseCapability.m_resolveFunction);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Reject, promiseCapability.m_rejectFunction);
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::RemainingElements, remainingElementsCount);
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1.
*remainingElementsCount = *remainingElementsCount + 1;
// Perform ? Invoke(nextPromise, "then", « resolveElement, resultCapability.[[Reject]] »).
Object* nextPromiseObject = nextPromise.toObject(state);
Value argv[] = { Value(resolveElement), Value(promiseCapability.m_rejectFunction) };
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv);
// Increase index by 1.
index++;
// Repeat
while (true) {
// Let next be IteratorStep(iteratorRecord).
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
if (UNLIKELY(state.hasPendingException())) {
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(next).
goto IfAbrupt;
}
} catch (const Value& v) {
Value exceptionValue = v;
// If result is an abrupt completion,
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
// IfAbruptRejectPromise(result, promiseCapability).
try {
if (!iteratorRecord->m_done) {
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
// If next is false,
if (!next.hasValue()) {
// set iteratorRecord.[[done]] to true.
iteratorRecord->m_done = true;
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] 1.
*remainingElementsCount = *remainingElementsCount - 1;
// If remainingElementsCount.[[value]] is 0,
if (*remainingElementsCount == 0) {
// Let valuesArray be CreateArrayFromList(values).
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
Value argv = Object::createArrayFromList(state, *values);
Value resolveResult = Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &argv);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
}
} catch (const Value& v) {
// ignore error value
// Return resultCapability.[[Promise]].
result = promiseCapability.m_promise;
break;
}
// Let nextValue be IteratorValue(next).
Value nextValue = IteratorObject::iteratorValue(state, next.value());
if (UNLIKELY(state.hasPendingException())) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(nextValue).
goto IfAbrupt;
}
// Append undefined to values.
values->pushBack(Value());
// Let nextPromise be Invoke(constructor, "resolve", « nextValue »).
Value nextPromise = Object::call(state, promiseResolve, C, 1, &nextValue);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
// Return capability.[[Promise]].
return promiseCapability.m_promise;
// Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
ExtendedNativeFunctionObject* resolveElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAllResolveElementFunction, 1, NativeFunctionInfo::Strict));
// Set the [[AlreadyCalled]] internal slot of resolveElement to a new Record {[[value]]: false }.
// Set the [[Index]] internal slot of resolveElement to index.
// Set the [[Values]] internal slot of resolveElement to values.
// Set the [[Capabilities]] internal slot of resolveElement to resultCapability.
// Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount.
bool* alreadyCalled = new (PointerFreeGC) bool(false);
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::AlreadyCalled, alreadyCalled);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Index, Value(index));
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::Values, values);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Resolve, promiseCapability.m_resolveFunction);
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Reject, promiseCapability.m_rejectFunction);
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::RemainingElements, remainingElementsCount);
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1.
*remainingElementsCount = *remainingElementsCount + 1;
// Perform ? Invoke(nextPromise, "then", « resolveElement, resultCapability.[[Reject]] »).
Object* nextPromiseObject = nextPromise.toObject(state);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
Value argv[] = { Value(resolveElement), Value(promiseCapability.m_rejectFunction) };
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
Object::call(state, callee, nextPromiseObject, 2, argv);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
// Increase index by 1.
index++;
}
// Return Completion(result).
return result;
IfAbrupt:
ASSERT(state.hasPendingException());
Value exceptionValue = state.detachPendingException();
// If result is an abrupt completion,
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
// IfAbruptRejectPromise(result, promiseCapability).
if (!iteratorRecord->m_done) {
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
if (UNLIKELY(state.hasPendingException())) {
exceptionValue = state.detachPendingException();
}
}
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
static Value builtinPromiseRace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@ -237,113 +246,121 @@ static Value builtinPromiseRace(ExecutionState& state, Value thisValue, size_t a
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
if (!thisValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->race.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->race.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
}
Object* C = thisValue.asObject();
// Let promiseCapability be NewPromiseCapability(C).
// ReturnIfAbrupt(promiseCapability).
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let promiseResolve be GetPromiseResolve(C).
Value resolve;
try {
resolve = getPromiseResolve(state, C);
} catch (const Value& v) {
Value thrownValue = v;
Value resolve = getPromiseResolve(state, C);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let iteratorRecord be GetIterator(iterable).
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
IteratorRecord* record;
try {
record = IteratorObject::getIterator(state, argv[0]);
} catch (const Value& v) {
Value thrownValue = v;
IteratorRecord* record = IteratorObject::getIterator(state, argv[0]);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Let rejectResult be Call(capability.[[Reject]], undefined, «value.[[value]]»).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
Value result;
try {
// Repeat
while (true) {
// Let next be IteratorStep(iteratorRecord).
Optional<Object*> next;
try {
next = IteratorObject::iteratorStep(state, record);
} catch (const Value& e) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
// ReturnIfAbrupt(next).
record->m_done = true;
state.throwException(e);
}
// If next is false, then
if (!next.hasValue()) {
// Set iteratorRecord.[[done]] to true.
record->m_done = true;
// Return resultCapability.[[Promise]].
result = promiseCapability.m_promise;
break;
}
// Let nextValue be IteratorValue(next).
Value nextValue;
try {
nextValue = IteratorObject::iteratorValue(state, next.value());
} catch (const Value& e) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
record->m_done = true;
// ReturnIfAbrupt(next).
state.throwException(e);
}
// Let nextPromise be Invoke(C, "resolve", «nextValue»).
Value nextPromise = Object::call(state, resolve, C, 1, &nextValue);
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
Object* nextPromiseObject = nextPromise.toObject(state);
Value argv[] = { Value(promiseCapability.m_resolveFunction), Value(promiseCapability.m_rejectFunction) };
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv);
// Repeat
while (true) {
// Let next be IteratorStep(iteratorRecord).
Optional<Object*> next = IteratorObject::iteratorStep(state, record);
if (UNLIKELY(state.hasPendingException())) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
// ReturnIfAbrupt(next).
record->m_done = true;
goto IfAbrupt;
}
} catch (const Value& e) {
Value exceptionValue = e;
// If result is an abrupt completion, then
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
// IfAbruptRejectPromise(result, promiseCapability).
try {
if (!record->m_done) {
result = IteratorObject::iteratorClose(state, record, exceptionValue, true);
}
} catch (const Value& v) {
// ignore error here
// If next is false, then
if (!next.hasValue()) {
// Set iteratorRecord.[[done]] to true.
record->m_done = true;
// Return resultCapability.[[Promise]].
result = promiseCapability.m_promise;
break;
}
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
// Return capability.[[Promise]].
return promiseCapability.m_promise;
// Let nextValue be IteratorValue(next).
Value nextValue = IteratorObject::iteratorValue(state, next.value());
if (UNLIKELY(state.hasPendingException())) {
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
record->m_done = true;
// ReturnIfAbrupt(next).
goto IfAbrupt;
}
// Let nextPromise be Invoke(C, "resolve", «nextValue»).
Value nextPromise = Object::call(state, resolve, C, 1, &nextValue);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
Object* nextPromiseObject = nextPromise.toObject(state);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
Value argv[] = { Value(promiseCapability.m_resolveFunction), Value(promiseCapability.m_rejectFunction) };
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
Object::call(state, callee, nextPromiseObject, 2, argv);
if (UNLIKELY(state.hasPendingException()))
goto IfAbrupt;
}
// Return Completion(result).
return result;
IfAbrupt:
ASSERT(state.hasPendingException());
Value exceptionValue = state.detachPendingException();
// If result is an abrupt completion, then
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
// IfAbruptRejectPromise(result, promiseCapability).
if (!record->m_done) {
result = IteratorObject::iteratorClose(state, record, exceptionValue, true);
if (UNLIKELY(state.hasPendingException())) {
exceptionValue = state.detachPendingException();
}
}
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
static Value builtinPromiseReject(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
auto strings = &state.context()->staticStrings();
Object* thisObject = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
PromiseReaction::Capability capability = PromiseObject::newPromiseCapability(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value arguments[] = { argv[0] };
Object::call(state, capability.m_rejectFunction, Value(), 1, arguments);
RETURN_VALUE_IF_PENDING_EXCEPTION
return capability.m_promise;
}
@ -354,7 +371,7 @@ static Value builtinPromiseResolve(ExecutionState& state, Value thisValue, size_
const Value& C = thisValue;
// If Type(C) is not Object, throw a TypeError exception.
if (!C.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Promise.string(), false, state.context()->staticStrings().resolve.string(), "%s: PromiseResolve called on non-object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Promise.string(), false, state.context()->staticStrings().resolve.string(), "%s: PromiseResolve called on non-object");
}
// Return ? PromiseResolve(C, x).
return PromiseObject::promiseResolve(state, C.asObject(), argv[0]);
@ -364,8 +381,10 @@ static Value builtinPromiseCatch(ExecutionState& state, Value thisValue, size_t
{
auto strings = &state.context()->staticStrings();
Object* thisObject = thisValue.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value onRejected = argv[0];
Value then = thisObject->get(state, strings->then).value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value arguments[] = { Value(), onRejected };
return Object::call(state, then, thisObject, 2, arguments);
}
@ -377,11 +396,12 @@ static Value builtinPromiseFinally(ExecutionState& state, Value thisValue, size_
auto strings = &state.context()->staticStrings();
if (!thisValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->finally.string(), "%s: not a Promise object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->finally.string(), "%s: not a Promise object");
}
Object* thisObject = thisValue.asObject();
Value C = thisObject->speciesConstructor(state, state.context()->globalObject()->promise());
RETURN_VALUE_IF_PENDING_EXCEPTION
Value onFinally = argv[0];
Value arguments[] = { onFinally, onFinally };
@ -400,16 +420,20 @@ static Value builtinPromiseFinally(ExecutionState& state, Value thisValue, size_
}
Value then = thisObject->get(state, strings->then).value(state, thisObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Object::call(state, then, thisObject, 2, arguments);
}
static Value builtinPromiseThen(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
auto strings = &state.context()->staticStrings();
if (!thisValue.isObject() || !thisValue.asObject()->isPromiseObject())
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->then.string(), "%s: not a Promise object");
if (!thisValue.isObject() || !thisValue.asObject()->isPromiseObject()) {
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->then.string(), "%s: not a Promise object");
}
Value C = thisValue.asObject()->speciesConstructor(state, state.context()->globalObject()->promise());
RETURN_VALUE_IF_PENDING_EXCEPTION
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C.asObject(), thisValue.asObject()->asPromiseObject());
RETURN_VALUE_IF_PENDING_EXCEPTION
return thisValue.asObject()->asPromiseObject()->then(state, argv[0], argv[1], promiseCapability).value();
}
@ -428,14 +452,12 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
// Repeat,
while (true) {
// Let next be IteratorStep(iteratorRecord).
Optional<Object*> next;
try {
next = IteratorObject::iteratorStep(state, iteratorRecord);
} catch (const Value& e) {
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
if (UNLIKELY(state.hasPendingException())) {
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(next).
state.throwException(e);
return Value(Value::Exception);
}
// If next is false, then
@ -450,20 +472,19 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
Value valuesArray = ArrayObject::createArrayFromList(state, *values);
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
Object::call(state, resultCapability.m_resolveFunction, Value(), 1, &valuesArray);
RETURN_VALUE_IF_PENDING_EXCEPTION
}
// Return resultCapability.[[Promise]].
return resultCapability.m_promise;
}
// Let nextValue be IteratorValue(next).
Value nextValue;
try {
nextValue = IteratorObject::iteratorValue(state, next.value());
} catch (const Value& e) {
Value nextValue = IteratorObject::iteratorValue(state, next.value());
if (UNLIKELY(state.hasPendingException())) {
// If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(nextValue).
state.throwException(e);
return Value(Value::Exception);
}
// Append undefined to values.
@ -471,6 +492,7 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
// Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Value nextValueArgv = nextValue;
Value nextPromise = Object::call(state, promiseResolve, constructor, 1, &nextValueArgv);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let steps be the algorithm steps defined in Promise.allSettled Resolve Element Functions.
// Let resolveElement be ! CreateBuiltinFunction(steps, « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
// Let alreadyCalled be the Record { [[Value]]: false }.
@ -507,7 +529,10 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
*remainingElementsCount = *remainingElementsCount + 1;
// Perform ? Invoke(nextPromise, "then", « resolveElement, rejectElement »).
Value argv[2] = { resolveElement, rejectElement };
Object::call(state, Object::getMethod(state, nextPromise, state.context()->staticStrings().then), nextPromise, 2, argv);
Value callee = Object::getMethod(state, nextPromise, state.context()->staticStrings().then);
RETURN_VALUE_IF_PENDING_EXCEPTION
Object::call(state, callee, nextPromise, 2, argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Set index to index + 1.
index++;
}
@ -521,66 +546,58 @@ static Value builtinPromiseAllSettled(ExecutionState& state, Value thisValue, si
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
if (!thisValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "this value of allSettled is not Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "this value of allSettled is not Object");
}
Object* C = thisValue.asObject();
// Let promiseCapability be ? NewPromiseCapability(C).
auto promiseCapability = PromiseObject::newPromiseCapability(state, C);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let promiseResolve be GetPromiseResolve(C).
Value promiseResolve;
try {
promiseResolve = getPromiseResolve(state, C);
} catch (const Value& v) {
Value thrownValue = v;
Value promiseResolve = getPromiseResolve(state, C);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let iteratorRecord be GetIterator(iterable).
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
IteratorRecord* iteratorRecord;
try {
iteratorRecord = IteratorObject::getIterator(state, argv[0]);
} catch (const Value& v) {
Value thrownValue = v;
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, argv[0]);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
Value result;
// Let result be PerformPromiseAllSettled(iteratorRecord, C, promiseCapability).
try {
result = performPromiseAllSettled(state, iteratorRecord, C, promiseCapability, promiseResolve);
} catch (const Value& v) {
Value exceptionValue = v;
Value result = performPromiseAllSettled(state, iteratorRecord, C, promiseCapability, promiseResolve);
if (UNLIKELY(state.hasPendingException())) {
Value exceptionValue = state.detachPendingException();
// If result is an abrupt completion,
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
if (!iteratorRecord->m_done) {
try {
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
} catch (const Value& v) {
// ignore error value
// IfAbruptRejectPromise(result, promiseCapability).
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
// Return capability.[[Promise]].
return promiseCapability.m_promise;
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
if (UNLIKELY(state.hasPendingException())) {
exceptionValue = state.detachPendingException();
} else {
return result;
}
} else {
// IfAbruptRejectPromise(result, promiseCapability).
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// IfAbruptRejectPromise(result, promiseCapability).
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Return Completion(result).
return result;
@ -603,12 +620,10 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
// Let next be IteratorStep(iteratorRecord).
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
// ReturnIfAbrupt(next).
Optional<Object*> next;
try {
next = IteratorObject::iteratorStep(state, iteratorRecord);
} catch (const Value& v) {
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
if (UNLIKELY(state.hasPendingException())) {
iteratorRecord->m_done = true;
state.throwException(v);
return Value(Value::Exception);
}
// If next is false, then
@ -625,28 +640,28 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
error->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")),
ObjectPropertyDescriptor(Object::createArrayFromList(state, *errors),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return ThrowCompletion(error).
state.throwException(error);
THROW_EXCEPTION_RETURN_VALUE(state, error);
}
// Return resultCapability.[[Promise]].
return resultCapability.m_promise;
}
// Let nextValue be IteratorValue(next).
Value nextValue;
try {
nextValue = IteratorObject::iteratorValue(state, next.value());
} catch (const Value& v) {
Value nextValue = IteratorObject::iteratorValue(state, next.value());
if (UNLIKELY(state.hasPendingException())) {
// If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
// ReturnIfAbrupt(nextValue).
state.throwException(v);
return Value(Value::Exception);
}
// Append undefined to errors.
errors->pushBack(Value());
// Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Value argv = nextValue;
Value nextPromise = Object::call(state, promiseResolve, constructor, 1, &argv);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let steps be the algorithm steps defined in Promise.any Reject Element Functions.
// Let rejectElement be ! CreateBuiltinFunction(steps, « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »).
ExtendedNativeFunctionObject* rejectElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAnyRejectElementFunction, 1, NativeFunctionInfo::Strict));
@ -667,8 +682,12 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »).
Object* nextPromiseObject = nextPromise.toObject(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
Value argv2[] = { Value(resultCapability.m_resolveFunction), Value(rejectElement) };
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv2);
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
RETURN_VALUE_IF_PENDING_EXCEPTION
Object::call(state, callee, nextPromiseObject, 2, argv2);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Set index to index + 1.
index++;
}
@ -683,22 +702,22 @@ static Value builtinPromiseAny(ExecutionState& state, Value thisValue, size_t ar
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
if (!thisValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
}
Object* C = thisValue.asObject();
// Let promiseCapability be NewPromiseCapability(C).
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Let promiseResolve be GetPromiseResolve(C).
// IfAbruptRejectPromise(promiseResolve, promiseCapability).
Value promiseResolve;
try {
promiseResolve = getPromiseResolve(state, C);
} catch (const Value& v) {
Value thrownValue = v;
Value promiseResolve = getPromiseResolve(state, C);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
@ -706,109 +725,46 @@ static Value builtinPromiseAny(ExecutionState& state, Value thisValue, size_t ar
// Let iteratorRecord be GetIterator(iterable).
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
const Value& iterable = argv[0];
IteratorRecord* iteratorRecord = nullptr;
try {
iteratorRecord = IteratorObject::getIterator(state, iterable);
} catch (const Value& v) {
Value thrownValue = v;
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, iterable);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If value is an abrupt completion,
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
// Return capability.[[Promise]].
return promiseCapability.m_promise;
}
// Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability, promiseResolve).
Value result;
try {
result = performPromiseAny(state, iteratorRecord, C, promiseCapability, promiseResolve);
} catch (const Value& v) {
Value thrownValue = v;
Value result = performPromiseAny(state, iteratorRecord, C, promiseCapability, promiseResolve);
if (UNLIKELY(state.hasPendingException())) {
Value thrownValue = state.detachPendingException();
// If result is an abrupt completion, then
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
try {
if (!iteratorRecord->m_done) {
IteratorObject::iteratorClose(state, iteratorRecord, thrownValue, true);
if (!iteratorRecord->m_done) {
IteratorObject::iteratorClose(state, iteratorRecord, thrownValue, true);
if (UNLIKELY(state.hasPendingException())) {
thrownValue = state.detachPendingException();
}
} catch (const Value& v) {
// ignore error here
}
// IfAbruptRejectPromise(result, promiseCapability).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
RETURN_VALUE_IF_PENDING_EXCEPTION
return promiseCapability.m_promise;
}
// Return Completion(result).
return result;
}
// https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-promise.withResolvers
static Value builtinPromiseWithResolvers(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Let C be the this value.
const Value& C = thisValue;
// Let promiseCapability be ? NewPromiseCapability(C).
if (!C.isObject()) {
// NOTE: isConstructor will be checked on PromiseObject::newPromiseCapability function
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
}
auto promiseCapability = PromiseObject::newPromiseCapability(state, C.asObject());
// Let obj be OrdinaryObjectCreate(%Object.prototype%).
Object* obj = new Object(state);
StaticStrings* strings = &state.context()->staticStrings();
// Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]).
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->lazyPromise()),
ObjectPropertyDescriptor(promiseCapability.m_promise, ObjectPropertyDescriptor::AllPresent));
// Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]).
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->resolve),
ObjectPropertyDescriptor(promiseCapability.m_resolveFunction, ObjectPropertyDescriptor::AllPresent));
// Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]).
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->reject),
ObjectPropertyDescriptor(promiseCapability.m_rejectFunction, ObjectPropertyDescriptor::AllPresent));
// Return obj.
return obj;
}
// https://tc39.es/ecma262/#sec-promise.try
static Value builtinPromiseTry(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// 1. Let C be the this value.
const Value& C = thisValue;
// 2. If C is not an Object, throw a TypeError exception.
if (!C.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
}
// 3. Let promiseCapability be ? NewPromiseCapability(C).
auto promiseCapability = PromiseObject::newPromiseCapability(state, C.asObject());
// 4. Let status be Completion(Call(callback, undefined, args)).
Value exception = Value(Value::EmptyValue);
Value result;
try {
result = Object::call(state, argv[0], Value(), argc - 1, argv + 1);
} catch (const Value& error) {
exception = error;
}
// 5. If status is an abrupt completion, then
if (!exception.isEmpty()) {
// a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »).
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exception);
} else {
// 6. Else,
// a. Perform ? Call(promiseCapability.[[Resolve]], undefined, « status.[[Value]] »).
Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &result);
}
// 7. Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
void GlobalObject::initializePromise(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->promise(); }, nullptr);
return self->asGlobalObject()->promise();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Promise), nativeData, Value(Value::EmptyValue));
}
@ -834,24 +790,20 @@ void GlobalObject::installPromise(ExecutionState& state)
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Promise.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.4.1 Promise.all(iterable);
m_promiseAll = new NativeFunctionObject(state, NativeFunctionInfo(strings->all, builtinPromiseAll, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->all),
ObjectPropertyDescriptor(m_promiseAll,
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->all, builtinPromiseAll, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.4.3 Promise.race(iterable)
m_promiseRace = new NativeFunctionObject(state, NativeFunctionInfo(strings->race, builtinPromiseRace, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->race),
ObjectPropertyDescriptor(m_promiseRace,
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->race, builtinPromiseRace, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.4.4 Promise.reject(r)
m_promiseReject = new NativeFunctionObject(state, NativeFunctionInfo(strings->reject, builtinPromiseReject, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->reject),
ObjectPropertyDescriptor(m_promiseReject,
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->reject, builtinPromiseReject, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.4.5 Promise.resolve(r)
m_promiseResolve = new NativeFunctionObject(state, NativeFunctionInfo(strings->resolve, builtinPromiseResolve, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->resolve),
ObjectPropertyDescriptor(m_promiseResolve,
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->resolve, builtinPromiseResolve, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.5.1 Promise.prototype.catch(onRejected)
m_promisePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->stringCatch),
@ -869,24 +821,12 @@ void GlobalObject::installPromise(ExecutionState& state)
m_promise->setFunctionPrototype(state, m_promisePrototype);
// Promise.allSettled ( iterable )
m_promiseAllSettled = new NativeFunctionObject(state, NativeFunctionInfo(strings->allSettled, builtinPromiseAllSettled, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->allSettled),
ObjectPropertyDescriptor(m_promiseAllSettled,
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->allSettled, builtinPromiseAllSettled, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// Promise.any ( iterable )
m_promiseAny = new NativeFunctionObject(state, NativeFunctionInfo(strings->any, builtinPromiseAny, 1, NativeFunctionInfo::Strict));
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->any),
ObjectPropertyDescriptor(m_promiseAny,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// Promise.withResolvers()
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->withResolvers),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->withResolvers, builtinPromiseWithResolvers, 0, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// Promise.try()
m_promise->directDefineOwnProperty(state, ObjectPropertyName(strings->stringTry),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->stringTry, builtinPromiseTry, 1, NativeFunctionInfo::Strict)),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->any, builtinPromiseAny, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -33,14 +33,16 @@ static Value builtinProxyConstructor(ExecutionState& state, Value thisValue, siz
auto strings = &state.context()->staticStrings();
if (!newTarget.hasValue()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString(), "%s: calling a builtin Proxy constructor without new is forbidden");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: calling a builtin Proxy constructor without new is forbidden");
return Value();
}
Value target = argv[0];
Value handler = argv[1];
return ProxyObject::createProxy(state, target, handler);
ProxyObject* result = ProxyObject::createProxy(state, target, handler);
RETURN_VALUE_IF_PENDING_EXCEPTION
return result;
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-proxy-revocation-functions
@ -84,6 +86,7 @@ static Value builtinProxyRevocable(ExecutionState& state, Value thisValue, size_
// 1. Let p be ProxyCreate(target, handler).
Value proxy = ProxyObject::createProxy(state, target, handler);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 3. Let revoker be a new built-in function object as defined in 26.2.2.1.1.
// 4. Set the [[RevocableProxy]] internal slot of revoker to p.
@ -96,10 +99,12 @@ static Value builtinProxyRevocable(ExecutionState& state, Value thisValue, size_
// 6. Perform CreateDataProperty(result, "proxy", p).
result->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->proxy),
ObjectPropertyDescriptor(proxy, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
// 7. Perform CreateDataProperty(result, "revoke", revoker).
result->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->revoke),
ObjectPropertyDescriptor(revoker, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
RETURN_VALUE_IF_PENDING_EXCEPTION
// 8. Return result.
return result;
@ -107,9 +112,12 @@ static Value builtinProxyRevocable(ExecutionState& state, Value thisValue, size_
void GlobalObject::initializeProxy(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->proxy(); }, nullptr);
return self->asGlobalObject()->proxy();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Proxy), nativeData, Value(Value::EmptyValue));
}

View file

@ -39,11 +39,12 @@ static Value builtinReflectApply(ExecutionState& state, Value thisValue, size_t
// 1. If IsCallable(target) is false, throw a TypeError exception.
if (!target.isObject() || !target.asObject()->isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: calling a not-callable target in apply function is forbidden");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: calling a not-callable target in apply function is forbidden");
}
// 2. Let args be CreateListFromArrayLike(argumentsList).
auto args = Object::createListFromArrayLike(state, argList);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 5. Return Call(target, thisArgument, args).
return Object::call(state, target, thisArgument, args.size(), args.data());
@ -59,17 +60,18 @@ static Value builtinReflectConstruct(ExecutionState& state, Value thisValue, siz
// 1. If IsConstructor(target) is false, throw a TypeError exception.
if (!target.isConstructor()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.construct should has a construct method");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.construct should has a construct method");
}
// 2. If newTarget is not present, let newTarget be target.
// 3. Else, if IsConstructor(newTarget) is false, throw a TypeError exception.
if (!newTargetArg.isConstructor()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The new target of Reflect.construct should be a constructor");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The new target of Reflect.construct should be a constructor");
}
// 4. Let args be CreateListFromArrayLike(argumentsList).
auto args = Object::createListFromArrayLike(state, argList);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 6. Return Construct(target, args, newTarget).
return Object::construct(state, target, args.size(), args.data(), newTargetArg.asObject());
}
@ -82,20 +84,21 @@ static Value builtinReflectDefineProperty(ExecutionState& state, Value thisValue
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.defineProperty should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.defineProperty should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 3. Let desc be ToPropertyDescriptor(attributes).
if (!argv[2].isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The attributes of Reflect.defineProperty should be an Object");
}
ObjectPropertyDescriptor desc(state, argv[2].asObject());
RETURN_VALUE_IF_PENDING_EXCEPTION
// 6. Return target.[[DefineOwnProperty]](key, desc).
return Value(target.asObject()->defineOwnProperty(state, key, desc));
bool result = target.asObject()->defineOwnProperty(state, key, desc);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.deleteproperty
@ -106,14 +109,17 @@ static Value builtinReflectDeleteProperty(ExecutionState& state, Value thisValue
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.deleteProperty should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.deleteProperty should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. Return target.[[Delete]](key).
return Value(target.asObject()->deleteOwnProperty(state, key));
bool result = target.asObject()->deleteOwnProperty(state, key);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.get
@ -124,11 +130,12 @@ static Value builtinReflectGet(ExecutionState& state, Value thisValue, size_t ar
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.get should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.get should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. If receiver is not present, then
// 4.a. Let receiver be target.
@ -146,11 +153,12 @@ static Value builtinReflectGetOwnPropertyDescriptor(ExecutionState& state, Value
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.getOwnPropertyDescriptor should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getOwnPropertyDescriptor should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. Let desc be target.[[GetOwnProperty]](key).
ObjectGetResult desc = target.asObject()->getOwnProperty(state, key);
@ -167,7 +175,7 @@ static Value builtinReflectGetPrototypeOf(ExecutionState& state, Value thisValue
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.getPrototypeOf should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getPrototypeOf should be an Object");
}
// 2. Return target.[[GetPrototypeOf]]().
@ -182,14 +190,17 @@ static Value builtinReflectHas(ExecutionState& state, Value thisValue, size_t ar
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.has should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.has should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. Return target.[[HasProperty]](key).
return Value(target.asObject()->hasProperty(state, key));
auto result = target.asObject()->hasProperty(state, key);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.isextensible
@ -200,11 +211,13 @@ static Value builtinReflectIsExtensible(ExecutionState& state, Value thisValue,
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.isExtensible should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.isExtensible should be an Object");
}
// 2. Return target.[[IsExtensible]]().
return Value(target.asObject()->isExtensible(state));
bool result = target.asObject()->isExtensible(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.preventextensions
@ -215,11 +228,13 @@ static Value builtinReflectPreventExtensions(ExecutionState& state, Value thisVa
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.preventExtension should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
}
// 2. Return target.[[PreventExtensions]]().
return Value(target.asObject()->preventExtensions(state));
bool result = target.asObject()->preventExtensions(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.ownkeys
@ -230,11 +245,12 @@ static Value builtinReflectOwnKeys(ExecutionState& state, Value thisValue, size_
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.preventExtension should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
}
// 2. Let keys be target.[[OwnPropertyKeys]]().
// 3. ReturnIfAbrupt(keys).
auto keys = target.asObject()->ownPropertyKeys(state);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. Return CreateArrayFromList(keys).
return Object::createArrayFromList(state, keys.size(), keys.data());
}
@ -248,18 +264,21 @@ static Value builtinReflectSet(ExecutionState& state, Value thisValue, size_t ar
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.set should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.set should be an Object");
}
// 2. Let key be ToPropertyKey(propertyKey).
ObjectPropertyName key(state, argv[1]);
RETURN_VALUE_IF_PENDING_EXCEPTION
// 4. If receiver is not present, then
// 4.a. Let receiver be target.
Value receiver = argc > 3 ? argv[3] : target;
// 5. Return target.[[Set]](key, V, receiver).
return Value(target.asObject()->set(state, key, argv[2], receiver));
bool result = target.asObject()->set(state, key, argv[2], receiver);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.setprototypeof
@ -271,23 +290,28 @@ static Value builtinReflectSetPrototypeOf(ExecutionState& state, Value thisValue
// 1. If Type(target) is not Object, throw a TypeError exception.
if (!target.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The target of Reflect.setPrototypeOf should be an Object");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.setPrototypeOf should be an Object");
}
// 2. If Type(proto) is not Object and proto is not null, throw a TypeError exception
if (!proto.isObject() && !proto.isNull()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString(), "%s: The proto of Reflect.setPrototypeOf should be an Object or Null");
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The proto of Reflect.setPrototypeOf should be an Object or Null");
}
// 3. Return target.[[SetPrototypeOf]](proto).
return Value(target.asObject()->setPrototype(state, proto));
bool result = target.asObject()->setPrototype(state, proto);
RETURN_VALUE_IF_PENDING_EXCEPTION
return Value(result);
}
void GlobalObject::initializeReflect(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true, [](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
ASSERT(self->isGlobalObject());
return self->asGlobalObject()->reflect(); }, nullptr);
return self->asGlobalObject()->reflect();
},
nullptr);
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Reflect), nativeData, Value(Value::EmptyValue));
}

Some files were not shown because too many files have changed in this diff Show more