├── .github └── workflows │ ├── benchmark.yaml │ ├── build.yaml │ └── publish.yaml ├── .gitignore ├── .gitmodules ├── LICENSE.txt ├── README.md ├── benchmark ├── .gitignore ├── README.md ├── build.gradle.kts └── src │ ├── jvmMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── benchmark │ │ ├── DefineBindingsBenchmark.kt │ │ └── InvokeBindingsBenchmark.kt │ └── nativeMain │ └── kotlin │ └── com │ └── dokar │ └── quickjs │ └── benchmark │ ├── DefineBindingsBenchmark.kt │ └── InvokeBindingsBenchmark.kt ├── build.gradle.kts ├── buildSrc ├── .gitignore ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ └── dokar │ └── quickjs │ ├── Platform.kt │ ├── applyQuickJsNativeBuildTasks.kt │ ├── buildQuickJsNativeLibrary.kt │ └── disableUnsupportedPlatformTasks.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── media └── async-eval-demo.gif ├── quickjs-converter-ktxserialization ├── .gitignore ├── build.gradle.kts ├── gradle.properties └── src │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── conveter │ │ └── SerializableConverter.kt │ └── commonTest │ └── kotlin │ └── com │ └── dokar │ └── quickjs │ └── converter │ └── test │ └── SerializableConverterTest.kt ├── quickjs-converter-moshi ├── .gitignore ├── build.gradle.kts ├── gradle.properties └── src │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── conveter │ │ └── JsonClassConverter.kt │ └── jvmTest │ └── kotlin │ └── com │ └── dokar │ └── quickjs │ └── converter │ └── test │ └── JsonClassConverterTest.kt ├── quickjs ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── gradle.properties ├── native │ ├── .gitignore │ ├── CMakeLists.txt │ ├── README.md │ ├── cmake │ │ ├── zig-ar.cmd │ │ ├── zig-ar.sh │ │ ├── zig-ranlib.cmd │ │ ├── zig-ranlib.sh │ │ ├── zig-toolchain-ios_aarch64.cmake │ │ ├── zig-toolchain-ios_aarch64_simulator.cmake │ │ ├── zig-toolchain-ios_x64.cmake │ │ ├── zig-toolchain-linux_aarch64.cmake │ │ ├── zig-toolchain-linux_x64.cmake │ │ ├── zig-toolchain-macos_aarch64.cmake │ │ ├── zig-toolchain-macos_x64.cmake │ │ └── zig-toolchain-windows_x64.cmake │ ├── common │ │ ├── quickjs_version.c │ │ └── quickjs_version.h │ ├── jni │ │ ├── binding_bridge.c │ │ ├── binding_bridge.h │ │ ├── exception_util.c │ │ ├── exception_util.h │ │ ├── jni_globals.c │ │ ├── jni_globals.h │ │ ├── jni_globals_generated.c │ │ ├── jni_globals_generated.h │ │ ├── js_value_util.c │ │ ├── js_value_util.h │ │ ├── log_util.h │ │ ├── mapping │ │ │ ├── jni_types_util.c │ │ │ ├── jni_types_util.h │ │ │ ├── jobject_to_js_value.c │ │ │ ├── jobject_to_js_value.h │ │ │ ├── js_value_to_jobject.c │ │ │ └── js_value_to_jobject.h │ │ ├── promise_rejection_handler.c │ │ ├── promise_rejection_handler.h │ │ ├── quickjs_jni.c │ │ └── quickjs_jni.h │ └── winpthreads │ │ ├── COPYING │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── README │ │ ├── aclocal.m4 │ │ ├── build-aux │ │ ├── ar-lib │ │ ├── compile │ │ ├── config.guess │ │ ├── config.sub │ │ ├── depcomp │ │ ├── install-sh │ │ ├── ltmain.sh │ │ ├── missing │ │ └── test-driver │ │ ├── config.h.in │ │ ├── configure │ │ ├── configure.ac │ │ ├── include │ │ ├── pthread.h │ │ ├── pthread_compat.h │ │ ├── pthread_signal.h │ │ ├── pthread_time.h │ │ ├── pthread_unistd.h │ │ ├── sched.h │ │ └── semaphore.h │ │ ├── m4 │ │ ├── libtool.m4 │ │ ├── ltoptions.m4 │ │ ├── ltsugar.m4 │ │ ├── ltversion.m4 │ │ └── lt~obsolete.m4 │ │ ├── src │ │ ├── barrier.c │ │ ├── barrier.h │ │ ├── clock.c │ │ ├── cond.c │ │ ├── cond.h │ │ ├── libgcc │ │ │ ├── dll_dependency.S │ │ │ └── dll_math.c │ │ ├── misc.c │ │ ├── misc.h │ │ ├── mutex.c │ │ ├── nanosleep.c │ │ ├── ref.c │ │ ├── ref.h │ │ ├── rwlock.c │ │ ├── rwlock.h │ │ ├── sched.c │ │ ├── sem.c │ │ ├── sem.h │ │ ├── spinlock.c │ │ ├── thread.c │ │ ├── thread.h │ │ ├── version.rc │ │ ├── winpthread_internal.h │ │ └── wpth_ver.h │ │ ├── tests │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── t_clock_getres.c │ │ ├── t_clock_gettime.c │ │ ├── t_clock_nanosleep.c │ │ ├── t_clock_settime.c │ │ ├── t_nanosleep.c │ │ └── test.c │ │ └── tests_pthread │ │ ├── Bmakefile │ │ ├── ChangeLog │ │ ├── ChangeLog.2010 │ │ ├── ChangeLog.2013 │ │ ├── Debug.dsp │ │ ├── Debug.dsw │ │ ├── Debug.plg │ │ ├── Debug.txt │ │ ├── GNUmakefile │ │ ├── Makefile │ │ ├── README │ │ ├── README.BENCHTESTS │ │ ├── README.WINPTHREADS │ │ ├── SIZES.GC │ │ ├── SIZES.GCE │ │ ├── SIZES.VC │ │ ├── SIZES.VCE │ │ ├── SIZES.VSE │ │ ├── Wmakefile │ │ ├── barrier1.c │ │ ├── barrier2.c │ │ ├── barrier3.c │ │ ├── barrier4.c │ │ ├── barrier5.c │ │ ├── barrier6.c │ │ ├── benchlib.c │ │ ├── benchtest.h │ │ ├── benchtest1.c │ │ ├── benchtest2.c │ │ ├── benchtest3.c │ │ ├── benchtest4.c │ │ ├── benchtest5.c │ │ ├── cancel1.c │ │ ├── cancel2.c │ │ ├── cancel3.c │ │ ├── cancel4.c │ │ ├── cancel5.c │ │ ├── cancel6a.c │ │ ├── cancel6d.c │ │ ├── cancel7.c │ │ ├── cancel8.c │ │ ├── cancel9.c │ │ ├── cleanup0.c │ │ ├── cleanup1.c │ │ ├── cleanup2.c │ │ ├── cleanup3.c │ │ ├── condvar1.c │ │ ├── condvar1_1.c │ │ ├── condvar1_2.c │ │ ├── condvar2.c │ │ ├── condvar2_1.c │ │ ├── condvar3.c │ │ ├── condvar3_1.c │ │ ├── condvar3_2.c │ │ ├── condvar3_3.c │ │ ├── condvar4.c │ │ ├── condvar5.c │ │ ├── condvar6.c │ │ ├── condvar7.c │ │ ├── condvar8.c │ │ ├── condvar9.c │ │ ├── context1.c │ │ ├── count1.c │ │ ├── create1.c │ │ ├── create2.c │ │ ├── create3.c │ │ ├── delay1.c │ │ ├── delay2.c │ │ ├── detach1.c │ │ ├── equal1.c │ │ ├── errno1.c │ │ ├── exception1.c │ │ ├── exception2.c │ │ ├── exception3.c │ │ ├── exit1.c │ │ ├── exit2.c │ │ ├── exit3.c │ │ ├── exit4.c │ │ ├── exit5.c │ │ ├── eyal1.c │ │ ├── inherit1.c │ │ ├── join0.c │ │ ├── join1.c │ │ ├── join2.c │ │ ├── join3.c │ │ ├── kill1.c │ │ ├── loadfree.c │ │ ├── mutex1.c │ │ ├── mutex1e.c │ │ ├── mutex1n.c │ │ ├── mutex1r.c │ │ ├── mutex2.c │ │ ├── mutex2e.c │ │ ├── mutex2r.c │ │ ├── mutex3.c │ │ ├── mutex3e.c │ │ ├── mutex3r.c │ │ ├── mutex4.c │ │ ├── mutex5.c │ │ ├── mutex6.c │ │ ├── mutex6e.c │ │ ├── mutex6es.c │ │ ├── mutex6n.c │ │ ├── mutex6r.c │ │ ├── mutex6rs.c │ │ ├── mutex6s.c │ │ ├── mutex7.c │ │ ├── mutex7e.c │ │ ├── mutex7n.c │ │ ├── mutex7r.c │ │ ├── mutex8.c │ │ ├── mutex8e.c │ │ ├── mutex8n.c │ │ ├── mutex8r.c │ │ ├── once1.c │ │ ├── once2.c │ │ ├── once3.c │ │ ├── once4.c │ │ ├── priority1.c │ │ ├── priority2.c │ │ ├── reuse1.c │ │ ├── reuse2.c │ │ ├── runall.c │ │ ├── rwlock1.c │ │ ├── rwlock2.c │ │ ├── rwlock2_t.c │ │ ├── rwlock3.c │ │ ├── rwlock3_t.c │ │ ├── rwlock4.c │ │ ├── rwlock4_t.c │ │ ├── rwlock5.c │ │ ├── rwlock5_t.c │ │ ├── rwlock6.c │ │ ├── rwlock6_t.c │ │ ├── rwlock6_t2.c │ │ ├── rwlock7.c │ │ ├── rwlock8.c │ │ ├── self1.c │ │ ├── self2.c │ │ ├── semaphore1.c │ │ ├── semaphore2.c │ │ ├── semaphore3.c │ │ ├── semaphore4.c │ │ ├── semaphore4t.c │ │ ├── semaphore5.c │ │ ├── sizes.c │ │ ├── spin1.c │ │ ├── spin2.c │ │ ├── spin3.c │ │ ├── spin4.c │ │ ├── stress1.c │ │ ├── test.h │ │ ├── tryentercs.c │ │ ├── tryentercs2.c │ │ ├── tsd1.c │ │ ├── tsd2.c │ │ ├── valid1.c │ │ └── valid2.c └── src │ ├── androidMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── Platform.android.kt │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ ├── ExperimentalQuickJsApi.kt │ │ ├── MemoryUsage.kt │ │ ├── QuickJs.kt │ │ ├── QuickJsException.kt │ │ ├── alias │ │ └── dslAlias.kt │ │ ├── binding │ │ ├── Bindings.dsl.kt │ │ ├── Bindings.dsl.typedArg.kt │ │ ├── Bindings.kt │ │ ├── DslObjectBinding.kt │ │ ├── JsFunction.kt │ │ ├── JsObject.kt │ │ ├── JsObjectHandle.kt │ │ └── JsProperty.kt │ │ ├── converter │ │ ├── JsObjectConverter.kt │ │ ├── TypeConverter.kt │ │ ├── TypeConverters.kt │ │ ├── builtinTypes.kt │ │ └── castValueOr.kt │ │ └── util │ │ └── Mutex.ext.kt │ ├── commonTest │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── test │ │ ├── AsyncErrorHandlingTest.kt │ │ ├── AsyncFunctionsTest.kt │ │ ├── BindingTest.kt │ │ ├── CompileTest.kt │ │ ├── CustomTypeConverterTest.kt │ │ ├── DslAliasTest.kt │ │ ├── EvalErrorsTest.kt │ │ ├── FlowToAsyncIteratorTest.kt │ │ ├── JsPromiseTest.kt │ │ ├── ModulesTest.kt │ │ ├── MultiRuntimeTest.kt │ │ ├── MultiThreadShareRuntime.kt │ │ ├── MultiThreadStackOverflowTest.kt │ │ ├── QuickJsPropertiesTest.kt │ │ ├── TypeMappingTest.ByteArray.kt │ │ ├── TypeMappingTest.kt │ │ └── ValueCastingTest.kt │ ├── jniMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ ├── Platform.kt │ │ ├── QuickJs.jni.kt │ │ ├── alias │ │ └── dslAlias.jni.kt │ │ ├── binding │ │ ├── Bindings.reflect.kt │ │ └── JsObjectHandle.jni.kt │ │ └── converter │ │ └── castValueOr.jvm.kt │ ├── jniTest │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── test │ │ ├── JvmValueCastingTest.kt │ │ └── ReflectionBindingTest.kt │ ├── jvmMain │ ├── .gitignore │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── Platform.jvm.kt │ ├── nativeInterop │ └── cinterop │ │ └── quickjs.def │ └── nativeMain │ └── kotlin │ └── com │ └── dokar │ └── quickjs │ ├── QuickJs.native.kt │ ├── binding │ └── JsObjectHandle.native.kt │ ├── bridge │ ├── BindingFunctionData.kt │ ├── async.kt │ ├── defineFunction.kt │ ├── defineObject.kt │ ├── errors.kt │ ├── evaluate.kt │ ├── invokeJsFunction.kt │ ├── jsValueToKtValue.kt │ ├── ktValueToJsValue.kt │ ├── memoryUsage.kt │ ├── promiseRejectionHandler.kt │ └── useJsValue.kt │ ├── converter │ └── castValueOr.native.kt │ └── util │ ├── JSValueUtil.kt │ └── allocArray.kt ├── renovate.json ├── samples ├── js-eval │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidMain │ │ ├── .gitignore │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── quickjs │ │ │ │ └── sample │ │ │ │ └── eval │ │ │ │ └── MainActivity.kt │ │ ├── proguard-rules.pro │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ └── strings.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ └── data_extraction_rules.xml │ │ ├── commonMain │ │ ├── composeResources │ │ │ └── files │ │ │ │ └── signals-core.mjs │ │ └── kotlin │ │ │ └── quickjs │ │ │ └── sample │ │ │ └── eval │ │ │ ├── CodeSnippets.kt │ │ │ └── EvalScreen.kt │ │ └── desktopMain │ │ └── kotlin │ │ └── quickjs │ │ └── sample │ │ └── eval │ │ └── Main.kt ├── openai │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidMain │ │ ├── .gitignore │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── quickjs │ │ │ │ └── sample │ │ │ │ └── openai │ │ │ │ └── MainActivity.kt │ │ ├── proguard-rules.pro │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ └── strings.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ └── data_extraction_rules.xml │ │ ├── commonMain │ │ ├── composeResources │ │ │ └── files │ │ │ │ ├── openai.js │ │ │ │ └── web-fetch.js │ │ └── kotlin │ │ │ └── quickjs │ │ │ └── sample │ │ │ └── openai │ │ │ ├── OpenAISampleScreen.kt │ │ │ └── bindings │ │ │ ├── cleanup.kt │ │ │ ├── env.kt │ │ │ ├── fetch.kt │ │ │ └── setTimeout.kt │ │ └── desktopMain │ │ └── kotlin │ │ └── quickjs │ │ └── sample │ │ └── openai │ │ └── Main.kt └── repl │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── dokar │ │ └── quickjs │ │ └── sample │ │ └── repl │ │ └── ReplCliApp.kt │ ├── jvmMain │ └── kotlin │ │ └── ReplMain.kt │ └── nativeMain │ └── kotlin │ └── ReplMain.kt ├── scripts ├── .gitignore ├── bun.lockb ├── createBenchmarkResult.ts ├── generateJniGlobalsCFiles.mjs ├── package.json └── setupMultiplatformJdks.ts └── settings.gradle.kts /.github/workflows/benchmark.yaml: -------------------------------------------------------------------------------- 1 | name: Run benchmarks 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | benchmark: 8 | runs-on: ubuntu-latest 9 | 10 | permissions: 11 | contents: write 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | submodules: recursive 17 | 18 | - name: Setup JDK 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: '17' 22 | distribution: 'adopt' 23 | cache: gradle 24 | 25 | # Build system for C 26 | - name: Setup CMake 27 | uses: jwlawson/actions-setup-cmake@v2.0 28 | 29 | # CMake generator 30 | - name: Setup ninja-build 31 | uses: seanmiddleditch/gha-setup-ninja@master 32 | 33 | # Cross-compile native libraries 34 | - name: Setup Zig 35 | uses: goto-bus-stop/setup-zig@v2 36 | 37 | # Run js/ts scripts 38 | - name: Set Bun.js 39 | uses: oven-sh/setup-bun@v2 40 | with: 41 | bun-version: latest 42 | 43 | - name: Install multiplatform JDKs 44 | run: | 45 | bun scripts/setupMultiplatformJdks.ts 46 | printf "Exports:\n$(cat ~/java-home-vars-github.sh)" 47 | source ~/java-home-vars-github.sh 48 | 49 | - uses: gradle/actions/setup-gradle@v3 50 | 51 | - name: Grant execute permission for scripts 52 | run: | 53 | chmod +x gradlew 54 | chmod +x quickjs/native/cmake/zig-ar.sh 55 | chmod +x quickjs/native/cmake/zig-ranlib.sh 56 | 57 | - name: Run benchmarks 58 | run: bun scripts/createBenchmarkResult.ts 59 | 60 | - name: Commit results 61 | uses: stefanzweifel/git-auto-commit-action@v5 62 | with: 63 | commit_message: Update benchmark results 64 | file_pattern: 'benchmark/README.md' 65 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | matrix: 14 | os: [ ubuntu-latest, macos-latest ] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | submodules: recursive 22 | 23 | - name: Setup JDK 24 | uses: actions/setup-java@v4 25 | with: 26 | java-version: '17' 27 | distribution: 'adopt' 28 | cache: gradle 29 | 30 | # Build system for C 31 | - name: Setup CMake 32 | uses: jwlawson/actions-setup-cmake@v2.0 33 | 34 | # CMake generator 35 | - name: Setup ninja-build 36 | uses: seanmiddleditch/gha-setup-ninja@master 37 | 38 | # Cross-compile native libraries 39 | - name: Setup Zig 40 | uses: goto-bus-stop/setup-zig@v2 41 | 42 | # Run js/ts scripts 43 | - name: Set Bun.js 44 | uses: oven-sh/setup-bun@v2 45 | with: 46 | bun-version: latest 47 | 48 | - name: Install multiplatform JDKs 49 | run: | 50 | bun scripts/setupMultiplatformJdks.ts 51 | printf "Exports:\n$(cat ~/java-home-vars-github.sh)" 52 | source ~/java-home-vars-github.sh 53 | 54 | - uses: gradle/actions/setup-gradle@v3 55 | 56 | - name: Grant execute permission for scripts 57 | run: | 58 | chmod +x gradlew 59 | chmod +x quickjs/native/cmake/zig-ar.sh 60 | chmod +x quickjs/native/cmake/zig-ranlib.sh 61 | 62 | - name: Build 63 | run: ./gradlew build 64 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | runs-on: macos-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | submodules: recursive 14 | 15 | - name: Setup JDK 16 | uses: actions/setup-java@v4 17 | with: 18 | java-version: '17' 19 | distribution: 'adopt' 20 | cache: gradle 21 | 22 | # Build system for C 23 | - name: Setup CMake 24 | uses: jwlawson/actions-setup-cmake@v2.0 25 | 26 | # CMake generator 27 | - name: Setup ninja-build 28 | uses: seanmiddleditch/gha-setup-ninja@master 29 | 30 | # Cross-compile native libraries 31 | - name: Setup Zig 32 | uses: goto-bus-stop/setup-zig@v2 33 | 34 | # Run js/ts scripts 35 | - name: Set Bun.js 36 | uses: oven-sh/setup-bun@v2 37 | with: 38 | bun-version: latest 39 | 40 | - name: Install multiplatform JDKs 41 | run: | 42 | bun scripts/setupMultiplatformJdks.ts 43 | printf "Exports:\n$(cat ~/java-home-vars-github.sh)" 44 | source ~/java-home-vars-github.sh 45 | 46 | - uses: gradle/actions/setup-gradle@v3 47 | 48 | - name: Grant execute permission for scripts 49 | run: | 50 | chmod +x gradlew 51 | chmod +x quickjs/native/cmake/zig-ar.sh 52 | chmod +x quickjs/native/cmake/zig-ranlib.sh 53 | 54 | - name: Publish to Sonatype 55 | run: ./gradlew publish --no-configuration-cache 56 | env: 57 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 58 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 59 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} 60 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.GPG_KEY_ID }} 61 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_KEY_PASSWORD }} 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | .kotlin 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "quickjs/native/quickjs"] 2 | path = quickjs/native/quickjs 3 | url = https://github.com/bellard/quickjs.git 4 | [submodule "quickjs/native/c-vector"] 5 | path = quickjs/native/c-vector 6 | url = https://github.com/eteran/c-vector.git 7 | -------------------------------------------------------------------------------- /benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark Results 2 | 3 | Generated on 7/2/2024, 1:39:51 PM 4 | 5 | Version: 1.0.0-alpha12 6 | 7 | ### Test environment 8 | 9 | System: linux x64 10 | 11 | CPUs: AMD EPYC 7763 64-Core Processor x 4 12 | 13 | Memory: 15.6 GB 14 | 15 | ### JVM Results 16 | 17 | | Name | Iterations | Score | Unit | 18 | | --- | --- | --- | --- | 19 | | defineDslBindings | 5 | 2211.57 | ops/s | 20 | | defineReflectionBindings | 5 | 2211.81 | ops/s | 21 | | invokeDslBindings | 5 | 37959.13 | ops/s | 22 | | invokeReflectionBindings | 5 | 41269.80 | ops/s | 23 | 24 | ### Kotlin/Native Results 25 | 26 | | Name | Iterations | Score | Unit | 27 | | --- | --- | --- | --- | 28 | | defineDslBindings | 5 | 2147.95 | ops/sec | 29 | | invokeDslBindings | 5 | 23507.90 | ops/sec | 30 | 31 | ### Notes 32 | 33 | The engine creation times are included in define[Xzy]Bindings benchmarks, so the actual results should be much faster, but the relative results should remain the same. 34 | -------------------------------------------------------------------------------- /benchmark/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.disableUnsupportedPlatformTasks 2 | 3 | plugins { 4 | alias(libs.plugins.kotlinMultiplatform) 5 | alias(libs.plugins.kotlinBenchmark) 6 | alias(libs.plugins.kotlinAllOpen) 7 | } 8 | 9 | kotlin { 10 | jvm() 11 | 12 | mingwX64() 13 | linuxX64() 14 | 15 | sourceSets { 16 | commonMain { 17 | dependencies { 18 | implementation(projects.quickjs) 19 | implementation(libs.kotlinx.coroutines.core) 20 | implementation(libs.kotlinx.benchmark.runtime) 21 | } 22 | } 23 | } 24 | } 25 | 26 | benchmark { 27 | targets { 28 | register("jvm") 29 | register("mingwX64") 30 | register("linuxX64") 31 | } 32 | } 33 | 34 | allOpen { 35 | annotation("org.openjdk.jmh.annotations.State") 36 | } 37 | 38 | disableUnsupportedPlatformTasks() 39 | -------------------------------------------------------------------------------- /benchmark/src/jvmMain/kotlin/com/dokar/quickjs/benchmark/DefineBindingsBenchmark.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.benchmark 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.define 5 | import kotlinx.benchmark.Benchmark 6 | import kotlinx.benchmark.Scope 7 | import kotlinx.benchmark.State 8 | import kotlinx.coroutines.Dispatchers 9 | 10 | @Suppress("unused") 11 | @State(Scope.Benchmark) 12 | class DefineBindingsBenchmark { 13 | @Benchmark 14 | fun defineDslBindings() { 15 | QuickJs.create(Dispatchers.Default).use { quickJs -> 16 | quickJs.define("http") { 17 | asyncFunction("fetch") {} 18 | } 19 | quickJs.define("console") { 20 | function("debug") {} 21 | function("log") {} 22 | function("info") {} 23 | function("warn") {} 24 | function("error") {} 25 | } 26 | quickJs.define("app") { 27 | property("name") { 28 | getter { "MyApp" } 29 | } 30 | 31 | property("version") { 32 | getter { "1.0.0" } 33 | } 34 | 35 | function("run") {} 36 | } 37 | } 38 | } 39 | 40 | @Benchmark 41 | fun defineReflectionBindings() { 42 | QuickJs.create(Dispatchers.Default).use { quickJs -> 43 | quickJs.define("http", Http::class.java, Http()) 44 | quickJs.define("console", Console::class.java, Console()) 45 | quickJs.define("app", App::class.java, App()) 46 | } 47 | } 48 | 49 | private class Http { 50 | suspend fun fetch() {} 51 | } 52 | 53 | private class Console { 54 | fun debug() {} 55 | fun log() {} 56 | fun info() {} 57 | fun warn() {} 58 | fun error() {} 59 | } 60 | 61 | private class App { 62 | val version: String = "1.0.0" 63 | val name: String = "MyApp" 64 | 65 | fun run() {} 66 | } 67 | } -------------------------------------------------------------------------------- /benchmark/src/jvmMain/kotlin/com/dokar/quickjs/benchmark/InvokeBindingsBenchmark.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.benchmark 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.define 5 | import kotlinx.benchmark.Benchmark 6 | import kotlinx.benchmark.Scope 7 | import kotlinx.benchmark.Setup 8 | import kotlinx.benchmark.State 9 | import kotlinx.benchmark.TearDown 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.runBlocking 12 | 13 | @Suppress("unused") 14 | @State(Scope.Benchmark) 15 | class InvokeBindingsBenchmark { 16 | private lateinit var quickJs: QuickJs 17 | 18 | @Setup 19 | fun setup() { 20 | quickJs = QuickJs.create(Dispatchers.Default) 21 | quickJs.define("dslConsole") { 22 | property("level") { 23 | getter { "Debug" } 24 | } 25 | 26 | function("log") {} 27 | } 28 | quickJs.define("reflectionConsole", Console::class.java, Console()) 29 | } 30 | 31 | @TearDown 32 | fun cleanup() { 33 | quickJs.close() 34 | } 35 | 36 | @Benchmark 37 | fun invokeDslBindings() = runBlocking { 38 | quickJs.evaluate("dslConsole.level") 39 | quickJs.evaluate("dslConsole.log()") 40 | } 41 | 42 | @Benchmark 43 | fun invokeReflectionBindings() = runBlocking { 44 | quickJs.evaluate("reflectionConsole.level") 45 | quickJs.evaluate("reflectionConsole.log()") 46 | } 47 | 48 | private class Console { 49 | val level = "Debug" 50 | 51 | fun log() {} 52 | } 53 | } -------------------------------------------------------------------------------- /benchmark/src/nativeMain/kotlin/com/dokar/quickjs/benchmark/DefineBindingsBenchmark.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.benchmark 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.define 5 | import kotlinx.benchmark.Benchmark 6 | import kotlinx.benchmark.Scope 7 | import kotlinx.benchmark.State 8 | import kotlinx.coroutines.Dispatchers 9 | 10 | @Suppress("unused") 11 | @State(Scope.Benchmark) 12 | class DefineBindingsBenchmark { 13 | @Benchmark 14 | fun defineDslBindings() { 15 | val quickJs = QuickJs.create(Dispatchers.Default) 16 | try { 17 | quickJs.define("http") { 18 | asyncFunction("fetch") {} 19 | } 20 | quickJs.define("console") { 21 | function("debug") {} 22 | function("log") {} 23 | function("info") {} 24 | function("warn") {} 25 | function("error") {} 26 | } 27 | quickJs.define("app") { 28 | property("name") { 29 | getter { "MyApp" } 30 | } 31 | 32 | property("version") { 33 | getter { "1.0.0" } 34 | } 35 | 36 | function("run") {} 37 | } 38 | quickJs.close() 39 | } finally { 40 | quickJs.close() 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /benchmark/src/nativeMain/kotlin/com/dokar/quickjs/benchmark/InvokeBindingsBenchmark.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.benchmark 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.define 5 | import kotlinx.benchmark.Benchmark 6 | import kotlinx.benchmark.Scope 7 | import kotlinx.benchmark.Setup 8 | import kotlinx.benchmark.State 9 | import kotlinx.benchmark.TearDown 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.runBlocking 12 | 13 | @Suppress("unused") 14 | @State(Scope.Benchmark) 15 | class InvokeBindingsBenchmark { 16 | private lateinit var quickJs: QuickJs 17 | 18 | @Setup 19 | fun setup() { 20 | quickJs = QuickJs.create(Dispatchers.Default) 21 | quickJs.define("dslConsole") { 22 | property("level") { 23 | getter { "Debug" } 24 | } 25 | 26 | function("log") {} 27 | } 28 | } 29 | 30 | @TearDown 31 | fun cleanup() { 32 | quickJs.close() 33 | } 34 | 35 | @Benchmark 36 | fun invokeDslBindings() = runBlocking { 37 | quickJs.evaluate("dslConsole.level") 38 | quickJs.evaluate("dslConsole.log()") 39 | } 40 | } -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | // this is necessary to avoid the plugins to be loaded multiple times 3 | // in each subproject's classloader 4 | alias(libs.plugins.androidApplication) apply false 5 | alias(libs.plugins.androidLibrary) apply false 6 | alias(libs.plugins.jetbrainsCompose) apply false 7 | alias(libs.plugins.kotlinJvm) apply false 8 | alias(libs.plugins.kotlinMultiplatform) apply false 9 | alias(libs.plugins.jetbrainsKotlinAndroid) apply false 10 | alias(libs.plugins.compose.compiler) apply false 11 | alias(libs.plugins.serialization) apply false 12 | alias(libs.plugins.ksp) apply false 13 | } -------------------------------------------------------------------------------- /buildSrc/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl-base` 3 | } 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "buildSrc" 2 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/com/dokar/quickjs/Platform.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | enum class Platform( 4 | val osName: String, 5 | val osArch: String, 6 | ) { 7 | linux_aarch64("linux", "aarch64"), 8 | linux_x64("linux", "x64"), 9 | macos_aarch64("macos", "aarch64"), 10 | macos_x64("macos", "x64"), 11 | ios_x64("ios", "x64"), 12 | ios_aarch64("ios", "aarch64"), 13 | ios_simulator_aarch64("ios_simulator", "aarch64"), 14 | windows_x64("windows", "x64"); 15 | } 16 | 17 | val currentPlatform: Platform by lazy { currentPlatform() } 18 | 19 | private fun currentPlatform(): Platform { 20 | val osName = System.getProperty("os.name").lowercase() 21 | val osArch = System.getProperty("os.arch").lowercase() 22 | val name = if (osName.contains("windows")) { 23 | "windows" 24 | } else if (osName.contains("linux")) { 25 | "linux" 26 | } else if (osName.contains("mac")) { 27 | "macos" 28 | } else { 29 | osName 30 | } 31 | val arch = when (osArch) { 32 | "aarch64" -> osArch 33 | "amd64", "x86_64" -> "x64" 34 | else -> osArch 35 | } 36 | for (platform in Platform.values()) { 37 | if (platform.osName == name && platform.osArch == arch) { 38 | return platform 39 | } 40 | } 41 | throw IllegalStateException("Unsupported os, name: $osName, arch: $osArch") 42 | } -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/com/dokar/quickjs/disableUnsupportedPlatformTasks.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | import org.gradle.api.Project 4 | 5 | fun Project.disableUnsupportedPlatformTasks() { 6 | tasks.configureEach { 7 | val isPublishing = gradle.startParameter.taskNames.contains("publish") 8 | if (isPublishing) { 9 | return@configureEach 10 | } 11 | val taskName = name.lowercase() 12 | if (taskName.contains("linuxx64")) { 13 | enabled = currentPlatform == Platform.linux_x64 14 | } else if (taskName.contains("linuxarm64")) { 15 | enabled = currentPlatform == Platform.linux_aarch64 16 | } else if (taskName.contains("mingwx64")) { 17 | enabled = currentPlatform == Platform.windows_x64 18 | } else if (taskName.contains("macosx64")) { 19 | enabled = currentPlatform == Platform.macos_x64 20 | } else if (taskName.contains("macosarm64")) { 21 | enabled = currentPlatform == Platform.macos_aarch64 22 | } else if (taskName.contains("iosx64")) { 23 | enabled = currentPlatform == Platform.macos_x64 24 | } else if (taskName.contains("iosarm64")) { 25 | enabled = currentPlatform == Platform.macos_aarch64 26 | } else if (taskName.contains("iossimulatorarm64")) { 27 | enabled = currentPlatform == Platform.macos_aarch64 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. For more details, visit 12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | 25 | kotlin.mpp.enableCInteropCommonization=true 26 | kotlin.native.cacheKind.linuxX64=none 27 | 28 | #Maven Publish 29 | SONATYPE_HOST=S01 30 | RELEASE_SIGNING_ENABLED=true 31 | 32 | GROUP=io.github.dokar3 33 | VERSION_NAME=1.0.0-alpha13 34 | 35 | POM_NAME=quickjs-kt 36 | POM_DESCRIPTION=A QuickJS binding for idiomatic Kotlin, with Async/DSL/ES Modules support. 37 | POM_INCEPTION_YEAR=2024 38 | POM_URL=https://github.com/dokar3/quickjs-kt 39 | 40 | POM_LICENSE_NAME=The Apache Software License, Version 2.0 41 | POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt 42 | POM_LICENSE_DIST=repo 43 | 44 | POM_SCM_URL=https://github.com/dokar3/quickjs-kt 45 | POM_SCM_CONNECTION=scm:git:git://github.com/dokar3/quickjs-kt.git 46 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/dokar3/quickjs-kt.git 47 | 48 | POM_DEVELOPER_ID=dokar3 49 | POM_DEVELOPER_NAME=Dokar 50 | POM_DEVELOPER_URL=https://github.com/dokar3/ -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /media/async-eval-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/media/async-eval-demo.gif -------------------------------------------------------------------------------- /quickjs-converter-ktxserialization/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /quickjs-converter-ktxserialization/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.disableUnsupportedPlatformTasks 2 | 3 | plugins { 4 | alias(libs.plugins.kotlinMultiplatform) 5 | alias(libs.plugins.androidLibrary) 6 | alias(libs.plugins.mavenPublish) 7 | alias(libs.plugins.serialization) 8 | } 9 | 10 | kotlin { 11 | androidTarget { 12 | publishLibraryVariants("release") 13 | } 14 | jvm() 15 | 16 | mingwX64() 17 | linuxX64() 18 | linuxArm64() 19 | macosX64() 20 | macosArm64() 21 | iosX64() 22 | iosArm64() 23 | iosSimulatorArm64() 24 | 25 | applyDefaultHierarchyTemplate() 26 | 27 | jvmToolchain { 28 | languageVersion.set(JavaLanguageVersion.of(11)) 29 | } 30 | 31 | sourceSets { 32 | val commonMain by getting { 33 | dependencies { 34 | implementation(project(":quickjs")) 35 | implementation(libs.kotlinx.coroutines.core) 36 | implementation(libs.kotlinx.serialization.properties) 37 | } 38 | } 39 | 40 | commonTest.dependencies { 41 | implementation(libs.kotlin.test) 42 | implementation(libs.kotlinx.coroutines.test) 43 | } 44 | } 45 | } 46 | 47 | android { 48 | namespace = "com.dokar.quickjs.converter.ktxserialization" 49 | compileSdk = libs.versions.android.compileSdk.get().toInt() 50 | 51 | defaultConfig { 52 | minSdk = libs.versions.android.minSdk.get().toInt() 53 | multiDexEnabled = true 54 | 55 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 56 | consumerProguardFiles("consumer-rules.pro") 57 | } 58 | } 59 | 60 | disableUnsupportedPlatformTasks() 61 | 62 | afterEvaluate { 63 | // Disable Android tests 64 | tasks.named("testDebugUnitTest").configure { 65 | enabled = false 66 | } 67 | tasks.named("testReleaseUnitTest").configure { 68 | enabled = false 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /quickjs-converter-ktxserialization/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=quickjs-kt-converter-ktxserialization 2 | POM_PACKAGING=aar 3 | -------------------------------------------------------------------------------- /quickjs-converter-ktxserialization/src/commonMain/kotlin/com/dokar/quickjs/conveter/SerializableConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.conveter 2 | 3 | import com.dokar.quickjs.binding.JsObject 4 | import com.dokar.quickjs.binding.toJsObject 5 | import com.dokar.quickjs.converter.JsObjectConverter 6 | import kotlinx.serialization.ExperimentalSerializationApi 7 | import kotlinx.serialization.properties.Properties 8 | import kotlinx.serialization.properties.decodeFromMap 9 | import kotlinx.serialization.properties.encodeToMap 10 | import kotlin.reflect.KType 11 | import kotlin.reflect.typeOf 12 | 13 | /** 14 | * Returns a [JsObjectConverter] for class [T]. 15 | * 16 | * Required [T] to be annotated with @[Serializable]. 17 | */ 18 | @OptIn(ExperimentalSerializationApi::class) 19 | @Suppress("FunctionName") 20 | inline fun SerializableConverter( 21 | properties: Properties = Properties 22 | ): JsObjectConverter { 23 | return object : JsObjectConverter { 24 | override val targetType: KType = typeOf() 25 | 26 | override fun convertToTarget(value: JsObject): T { 27 | val map = value.filterValues { it != null }.mapValues { it.value!! } 28 | return properties.decodeFromMap(map) 29 | } 30 | 31 | override fun convertToSource(value: T): JsObject { 32 | return properties.encodeToMap(value).toJsObject() 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /quickjs-converter-moshi/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /quickjs-converter-moshi/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.disableUnsupportedPlatformTasks 2 | 3 | plugins { 4 | alias(libs.plugins.kotlinMultiplatform) 5 | alias(libs.plugins.androidLibrary) 6 | alias(libs.plugins.mavenPublish) 7 | alias(libs.plugins.ksp) 8 | } 9 | 10 | kotlin { 11 | androidTarget { 12 | publishLibraryVariants("release") 13 | } 14 | jvm() 15 | 16 | applyDefaultHierarchyTemplate() 17 | 18 | jvmToolchain { 19 | languageVersion.set(JavaLanguageVersion.of(11)) 20 | } 21 | 22 | sourceSets { 23 | val commonMain by getting { 24 | dependencies { 25 | implementation(project(":quickjs")) 26 | implementation(libs.moshi) 27 | } 28 | } 29 | 30 | jvmTest.dependencies { 31 | implementation(libs.kotlin.test.junit) 32 | implementation(libs.kotlinx.coroutines.test) 33 | } 34 | } 35 | } 36 | 37 | android { 38 | namespace = "com.dokar.quickjs.converter.moshi" 39 | compileSdk = libs.versions.android.compileSdk.get().toInt() 40 | 41 | defaultConfig { 42 | minSdk = libs.versions.android.minSdk.get().toInt() 43 | multiDexEnabled = true 44 | 45 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 46 | consumerProguardFiles("consumer-rules.pro") 47 | } 48 | } 49 | 50 | dependencies { 51 | ksp(libs.moshi.kotlin.codegen) 52 | } 53 | 54 | disableUnsupportedPlatformTasks() 55 | 56 | afterEvaluate { 57 | // Disable Android tests 58 | tasks.named("testDebugUnitTest").configure { 59 | enabled = false 60 | } 61 | tasks.named("testReleaseUnitTest").configure { 62 | enabled = false 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /quickjs-converter-moshi/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=quickjs-kt-converter-moshi 2 | POM_PACKAGING=aar 3 | -------------------------------------------------------------------------------- /quickjs-converter-moshi/src/commonMain/kotlin/com/dokar/quickjs/conveter/JsonClassConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.conveter 2 | 3 | import com.dokar.quickjs.binding.JsObject 4 | import com.dokar.quickjs.binding.toJsObject 5 | import com.dokar.quickjs.converter.JsObjectConverter 6 | import com.squareup.moshi.JsonAdapter 7 | import com.squareup.moshi.JsonClass 8 | import com.squareup.moshi.Moshi 9 | import com.squareup.moshi.adapter 10 | import java.lang.reflect.Type 11 | import kotlin.reflect.KType 12 | import kotlin.reflect.typeOf 13 | 14 | /** 15 | * Returns a [JsObjectConverter] for class [T]. 16 | * 17 | * Required [T] to be annotated with moshi's @[JsonClass]. 18 | */ 19 | @OptIn(ExperimentalStdlibApi::class) 20 | @Suppress("FunctionName") 21 | inline fun JsonClassConverter( 22 | moshi: Moshi = Moshi.Builder().build() 23 | ): JsObjectConverter { 24 | return newConverter(adapter = moshi.adapter()) 25 | } 26 | 27 | /** 28 | * Returns a [JsObjectConverter] for class [T]. 29 | * 30 | * Required [T] to be annotated with moshi's @[JsonClass]. 31 | */ 32 | @Suppress("FunctionName") 33 | inline fun JsonClassConverter( 34 | type: Type, 35 | moshi: Moshi = Moshi.Builder().build() 36 | ): JsObjectConverter { 37 | return newConverter(adapter = moshi.adapter(type)) 38 | } 39 | 40 | @Suppress("UNCHECKED_CAST") 41 | @PublishedApi 42 | internal inline fun newConverter(adapter: JsonAdapter): JsObjectConverter { 43 | return object : JsObjectConverter { 44 | override val targetType: KType = typeOf() 45 | 46 | override fun convertToTarget(value: JsObject): T { 47 | return adapter.fromJsonValue(value) 48 | ?: throw IllegalStateException("Cannot convert js object to type '${T::class}'") 49 | } 50 | 51 | override fun convertToSource(value: T): JsObject { 52 | return (adapter.toJsonValue(value) as Map).toJsObject() 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /quickjs/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cxx/ 3 | .gradle/ 4 | 5 | *.log 6 | -------------------------------------------------------------------------------- /quickjs/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -keep,allowoptimization class com.dokar.quickjs.QuickJs { *; } 2 | -keep,allowoptimization class com.dokar.quickjs.QuickJsException { *; } 3 | -keep,allowoptimization class com.dokar.quickjs.binding.JsProperty { *; } 4 | -keep,allowoptimization class com.dokar.quickjs.binding.JsFunction { *; } 5 | -keep,allowoptimization class com.dokar.quickjs.binding.JsObject { *; } 6 | -keep,allowoptimization class kotlin.UByteArray 7 | -------------------------------------------------------------------------------- /quickjs/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=quickjs-kt 2 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /quickjs/native/.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /quickjs/native/README.md: -------------------------------------------------------------------------------- 1 | # JNI 2 | 3 | Using zig for cross-compiling, based on [zig-cross](https://github.com/mrexodia/zig-cross) 4 | 5 | ### Requirements 6 | 7 | - [Zig](https://ziglang.org/) 8 | - Windows, Linux, and macOS JDK 9 | - [CMake](https://cmake.org/) 10 | - Android NDK 11 | 12 | ### Build 13 | 14 | ```bash 15 | # Build Linux x64 16 | cmake ./ -B build/linux_x64 -G Ninja -DTARGET_PLATFORM=linux_x64 -DPLATFORM_JAVA_HOME=/path/to/linux_x64/java_home 17 | cmake --build ./build/linux_x64 18 | 19 | # Build Windows x64 20 | cmake ./ -B build/windows_x64 -G Ninja -DTARGET_PLATFORM=windows_x64 -DPLATFORM_JAVA_HOME=/path/to/windows_x64/java_home 21 | cmake --build ./build/windows_x64 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-ar.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | zig ar %* -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-ar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | zig ar "$@" 3 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-ranlib.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | zig ranlib %* -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-ranlib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | zig ranlib "$@" 3 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-ios_aarch64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "iOS") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 7 | set(CMAKE_C_COMPILER "zig" cc -target aarch64-ios) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target aarch64-ios) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-ios_aarch64_simulator.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "iOS") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 7 | set(CMAKE_C_COMPILER "zig" cc -target aarch64-ios-simulator) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target aarch64-ios-simulator) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-ios_x64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "iOS") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 7 | set(CMAKE_C_COMPILER "zig" cc -target x86_64-ios) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target x86_64-ios) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-linux_aarch64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "Linux") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 7 | # Add -fno-sanitize=undefined to suppress 'Illegal instruction' errors 8 | # https://github.com/ziglang/zig/wiki/FAQ#why-do-i-get-illegal-instruction-when-using-with-zig-cc-to-build-c-code 9 | set(CMAKE_C_COMPILER "zig" cc -target aarch64-linux-gnu -fno-sanitize=undefined) 10 | set(CMAKE_CXX_COMPILER "zig" c++ -target aarch64-linux-gnu -fno-sanitize=undefined) 11 | 12 | if(WIN32) 13 | set(SCRIPT_SUFFIX ".cmd") 14 | else() 15 | set(SCRIPT_SUFFIX ".sh") 16 | endif() 17 | 18 | # This is working (thanks to Simon for finding this trick) 19 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 20 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 21 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-linux_x64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "Linux") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 7 | # Add -fno-sanitize=undefined to suppress 'Illegal instruction' errors 8 | # https://github.com/ziglang/zig/wiki/FAQ#why-do-i-get-illegal-instruction-when-using-with-zig-cc-to-build-c-code 9 | set(CMAKE_C_COMPILER "zig" cc -target x86_64-linux-gnu -fno-sanitize=undefined) 10 | set(CMAKE_CXX_COMPILER "zig" c++ -target x86_64-linux-gnu -fno-sanitize=undefined) 11 | 12 | if(WIN32) 13 | set(SCRIPT_SUFFIX ".cmd") 14 | else() 15 | set(SCRIPT_SUFFIX ".sh") 16 | endif() 17 | 18 | # This is working (thanks to Simon for finding this trick) 19 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 20 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 21 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-macos_aarch64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "Darwin") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 7 | set(CMAKE_C_COMPILER "zig" cc -target aarch64-macos -fno-sanitize=undefined) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target aarch64-macos -fno-sanitize=undefined) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-macos_x64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "Darwin") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 7 | set(CMAKE_C_COMPILER "zig" cc -target x86_64-macos -fno-sanitize=undefined) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target x86_64-macos -fno-sanitize=undefined) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/cmake/zig-toolchain-windows_x64.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_GENERATOR MATCHES "Visual Studio") 2 | message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja") 3 | endif() 4 | set(CMAKE_SYSTEM_NAME "Windows") 5 | set(CMAKE_SYSTEM_VERSION 1) 6 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 7 | set(CMAKE_C_COMPILER "zig" cc -target x86_64-windows-gnu -fno-sanitize=undefined) 8 | set(CMAKE_CXX_COMPILER "zig" c++ -target x86_64-windows-gnu -fno-sanitize=undefined) 9 | 10 | if(WIN32) 11 | set(SCRIPT_SUFFIX ".cmd") 12 | else() 13 | set(SCRIPT_SUFFIX ".sh") 14 | endif() 15 | 16 | # This is working (thanks to Simon for finding this trick) 17 | set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}") 18 | set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}") 19 | -------------------------------------------------------------------------------- /quickjs/native/common/quickjs_version.c: -------------------------------------------------------------------------------- 1 | #include "quickjs_version.h" 2 | 3 | const char *quickjs_version() { 4 | #ifdef CONFIG_VERSION 5 | return CONFIG_VERSION; 6 | #else 7 | return "not_configured"; 8 | #endif 9 | } -------------------------------------------------------------------------------- /quickjs/native/common/quickjs_version.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_QUICKJS_VERSION_H 2 | #define QJS_KT_QUICKJS_VERSION_H 3 | 4 | /** 5 | * Get the version. 6 | */ 7 | const char *quickjs_version(); 8 | 9 | #endif //QJS_KT_QUICKJS_VERSION_H 10 | -------------------------------------------------------------------------------- /quickjs/native/jni/binding_bridge.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JS_BINDING_BRIDGE_H 2 | #define QJS_KT_JS_BINDING_BRIDGE_H 3 | 4 | #include "jni.h" 5 | #include "quickjs.h" 6 | #include "cvector.h" 7 | #include "quickjs_jni.h" 8 | 9 | /** 10 | * Define a JavaScript object. It will be attached to the parent if the parent is not null, 11 | * otherwise, it will be attached to 'globalThis'. 12 | */ 13 | JSValue define_js_object(JNIEnv *env, JSContext *context, 14 | Globals *globals, 15 | jobject call_host, 16 | JSValue *parent, 17 | int64_t handle, 18 | jstring name, 19 | jobjectArray properties, 20 | jobjectArray function_names); 21 | 22 | 23 | /** 24 | * Define a JavaScript function. It will be attached to 'globalThis'. 25 | */ 26 | void define_js_function(JNIEnv *env, JSContext *context, 27 | Globals *globals, 28 | jobject call_host, 29 | jstring name, 30 | jboolean is_async); 31 | 32 | #endif //QJS_KT_JS_BINDING_BRIDGE_H 33 | -------------------------------------------------------------------------------- /quickjs/native/jni/exception_util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "exception_util.h" 4 | #include "jni_globals_generated.h" 5 | #include "log_util.h" 6 | #include "js_value_util.h" 7 | 8 | jthrowable new_qjs_exception(JNIEnv *env, const char *format, ...) { 9 | va_list args; 10 | va_start(args, format); 11 | int length = vsnprintf(NULL, 0, format, args); 12 | va_end(args); 13 | 14 | char *result = (char *) malloc(length + 1); 15 | 16 | va_start(args, format); 17 | vsnprintf(result, length + 1, format, args); 18 | va_end(args); 19 | 20 | jstring message = (*env)->NewStringUTF(env, result); 21 | return (*env)->NewObject(env, cls_quick_js_exception(env), 22 | method_quick_js_exception_init(env), message); 23 | } 24 | 25 | void jni_throw_qjs_exception(JNIEnv *env, const char *format, ...) { 26 | va_list args; 27 | va_start(args, format); 28 | int length = vsnprintf(NULL, 0, format, args); 29 | va_end(args); 30 | 31 | char *result = (char *) malloc(length + 1); 32 | 33 | va_start(args, format); 34 | vsnprintf(result, length + 1, format, args); 35 | va_end(args); 36 | 37 | (*env)->ThrowNew(env, cls_quick_js_exception(env), result); 38 | } 39 | 40 | jthrowable try_catch_java_exceptions(JNIEnv *env) { 41 | jthrowable exception = (*env)->ExceptionOccurred(env); 42 | if (exception != NULL) { 43 | (*env)->ExceptionClear(env); 44 | return exception; 45 | } else { 46 | return NULL; 47 | } 48 | } 49 | 50 | int check_js_context_exception(JNIEnv *env, JSContext *context) { 51 | JSValue exception = JS_GetException(context); 52 | // Check exception 53 | if (!JS_IsNull(exception)) { 54 | char *message = NULL; 55 | js_error_to_string(context, exception, &message); 56 | // Free values 57 | JS_FreeValue(context, exception); 58 | // Throw java exception 59 | jni_throw_qjs_exception(env, message); 60 | return 1; 61 | } else { 62 | return 0; 63 | } 64 | } -------------------------------------------------------------------------------- /quickjs/native/jni/exception_util.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_EXCEPTION_UTIL_H 2 | #define QJS_KT_EXCEPTION_UTIL_H 3 | 4 | #include 5 | #include "jni.h" 6 | #include "quickjs.h" 7 | 8 | jthrowable new_qjs_exception(JNIEnv *env, const char *format, ...); 9 | 10 | void jni_throw_qjs_exception(JNIEnv *env, const char *format, ...); 11 | 12 | jthrowable try_catch_java_exceptions(JNIEnv *env); 13 | 14 | /** 15 | * Check and throw js context exception, if any. 16 | * 17 | * @return 1 if there is an exception in the context, 0 otherwise. 18 | */ 19 | int check_js_context_exception(JNIEnv *env, JSContext *context); 20 | 21 | #endif //QJS_KT_EXCEPTION_UTIL_H 22 | -------------------------------------------------------------------------------- /quickjs/native/jni/jni_globals.c: -------------------------------------------------------------------------------- 1 | #include "jni_globals.h" 2 | #include "log_util.h" 3 | 4 | static JavaVM *vm = NULL; 5 | 6 | void cache_java_vm(JNIEnv *env) { 7 | (*env)->GetJavaVM(env, &vm); 8 | } 9 | 10 | JNIEnv *get_jni_env() { 11 | if (vm == NULL) { 12 | log("Cannot get jni env because the vm is not cached."); 13 | return NULL; 14 | } 15 | JNIEnv *env = NULL; 16 | int attached = 0; 17 | jint get_env_result = (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6); 18 | if (get_env_result == JNI_OK) { 19 | attached = 1; 20 | } else if (get_env_result == JNI_EDETACHED) { 21 | // Got a warning on Android Studio when casting &env to (void **) 22 | #pragma clang diagnostic push 23 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 24 | if ((*vm)->AttachCurrentThread(vm, (void **) &env, NULL) == JNI_OK) { 25 | #pragma clang diagnostic pop 26 | attached = 1; 27 | } else { 28 | log("Failed to attach current thread."); 29 | } 30 | } else if (get_env_result == JNI_EVERSION) { 31 | log("Unsupported JNI version."); 32 | } 33 | if (attached == 0) { 34 | return NULL; 35 | } 36 | return env; 37 | } 38 | 39 | 40 | void clear_java_vm_cache() { 41 | vm = NULL; 42 | } -------------------------------------------------------------------------------- /quickjs/native/jni/jni_globals.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JNI_GLOBALS_H 2 | #define QJS_KT_JNI_GLOBALS_H 3 | 4 | #include "jni.h" 5 | 6 | void cache_java_vm(JNIEnv *env); 7 | 8 | JNIEnv *get_jni_env(); 9 | 10 | void clear_java_vm_cache(); 11 | 12 | #endif //QJS_KT_JNI_GLOBALS_H 13 | -------------------------------------------------------------------------------- /quickjs/native/jni/js_value_util.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JS_VALUE_UTIL_H 2 | #define QJS_KT_JS_VALUE_UTIL_H 3 | 4 | #include "quickjs.h" 5 | 6 | /** 7 | * Join array to string. 8 | * 9 | * @return NULL if failed to join, when successful, free() is required. 10 | */ 11 | char *js_array_join(JSContext *context, JSValue array, const char *separator); 12 | 13 | /** 14 | * Join the js error message and stack trace (if any). 15 | * 16 | * @param context The js context. 17 | * @param error The error js value. 18 | * @param out Destination string pointer. 19 | */ 20 | void js_error_to_string(JSContext *context, JSValue error, char **out); 21 | 22 | /** 23 | * Create a js error with a message field. 24 | */ 25 | JSValue new_simple_js_error(JSContext *context, const char *message); 26 | 27 | /** 28 | * Create a js error. 29 | */ 30 | JSValue new_js_error(JSContext *context, 31 | const char *name, 32 | const char *message, 33 | uint32_t stack_trace_lines, 34 | const char **stack_trace); 35 | 36 | /** 37 | * Check if the js value is a Promise. 38 | */ 39 | int js_is_promise(JSContext *context, JSValue value); 40 | 41 | /** 42 | * Check if the js value is a Promise. 43 | */ 44 | int js_is_promise_2(JSContext *context, JSValue global_this, JSValue value); 45 | 46 | /** 47 | * Check if the js value is a Uint8Array. 48 | */ 49 | int js_is_uint8array(JSContext *context, JSValue global_this, JSValue value); 50 | 51 | /** 52 | * Check if the js value is a Int8Array. 53 | */ 54 | int js_is_int8array(JSContext *context, JSValue global_this, JSValue value); 55 | 56 | /** 57 | * Check if the js value is a Set. 58 | */ 59 | int js_is_set(JSContext *context, JSValue global_this, JSValue value); 60 | 61 | /** 62 | * Check if the js value is a Map. 63 | */ 64 | int js_is_map(JSContext *context, JSValue global_this, JSValue value); 65 | 66 | /** 67 | * Get the value of a fulfilled promise. 68 | */ 69 | JSValue js_promise_get_fulfilled_value(JSContext *context, JSValue promise); 70 | 71 | #endif //QJS_KT_JS_VALUE_UTIL_H 72 | -------------------------------------------------------------------------------- /quickjs/native/jni/log_util.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_LOG_UTIL_H 2 | #define QJS_KT_LOG_UTIL_H 3 | 4 | #ifdef CONFIG_ANDROID 5 | 6 | #include 7 | 8 | #define log(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "QuickJSJni", fmt, ##__VA_ARGS__) 9 | #else 10 | #include 11 | 12 | #define log(fmt, ...) printf(fmt, ##__VA_ARGS__); printf("\n") 13 | #endif 14 | 15 | #endif //QJS_KT_LOG_UTIL_H 16 | -------------------------------------------------------------------------------- /quickjs/native/jni/mapping/jni_types_util.c: -------------------------------------------------------------------------------- 1 | #include "jni_types_util.h" 2 | #include "jni_globals_generated.h" 3 | 4 | jobject java_boxed_boolean(JNIEnv *env, jboolean value) { 5 | jclass cls = cls_boolean(env); 6 | jmethodID method = method_boolean_value_of(env); 7 | return (*env)->CallStaticObjectMethod(env, cls, method, value); 8 | } 9 | 10 | jobject java_boxed_long(JNIEnv *env, int64_t value) { 11 | jclass cls = cls_long(env); 12 | jmethodID method = method_long_value_of(env); 13 | return (*env)->CallStaticObjectMethod(env, cls, method, value); 14 | } 15 | 16 | jobject java_boxed_double(JNIEnv *env, jdouble value) { 17 | jclass cls = cls_double(env); 18 | jmethodID method = method_double_value_of(env); 19 | return (*env)->CallStaticObjectMethod(env, cls, method, value); 20 | } 21 | 22 | jobject java_boxed_nan_double(JNIEnv *env) { 23 | jclass cls = cls_double(env); 24 | jfieldID field = field_double_na_n(env); 25 | jdouble basic = (*env)->GetStaticDoubleField(env, cls, field); 26 | return java_boxed_double(env, basic); 27 | } 28 | -------------------------------------------------------------------------------- /quickjs/native/jni/mapping/jni_types_util.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JNI_TYPES_UTIL_H 2 | #define QJS_KT_JNI_TYPES_UTIL_H 3 | 4 | #include 5 | #include "jni.h" 6 | 7 | jobject java_boxed_boolean(JNIEnv *env, jboolean value); 8 | 9 | jobject java_boxed_long(JNIEnv *env, int64_t value); 10 | 11 | jobject java_boxed_double(JNIEnv *env, jdouble value); 12 | 13 | jobject java_boxed_nan_double(JNIEnv *env); 14 | 15 | #endif //QJS_KT_JNI_TYPES_UTIL_H 16 | -------------------------------------------------------------------------------- /quickjs/native/jni/mapping/jobject_to_js_value.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JOBJECT_TO_JS_VALUE_H 2 | #define QJS_KT_JOBJECT_TO_JS_VALUE_H 3 | 4 | #include "jni.h" 5 | #include "quickjs.h" 6 | 7 | /** 8 | * Convert java JsValue to QuickJS JsValue. 9 | */ 10 | JSValue jobject_to_js_value(JNIEnv *env, JSContext *context, jobject visited_set, jobject value); 11 | 12 | 13 | #endif //QJS_KT_JOBJECT_TO_JS_VALUE_H 14 | -------------------------------------------------------------------------------- /quickjs/native/jni/mapping/js_value_to_jobject.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JS_VALUE_TO_JOBJECT_H 2 | #define QJS_KT_JS_VALUE_TO_JOBJECT_H 3 | 4 | #include "jni.h" 5 | #include "quickjs.h" 6 | 7 | /** 8 | * Convert js value to java object. Throw an exception if the value type is unsupported. 9 | */ 10 | jobject js_value_to_jobject(JNIEnv *env, JSContext *context, JSValue value); 11 | 12 | #endif //QJS_KT_JS_VALUE_TO_JOBJECT_H 13 | -------------------------------------------------------------------------------- /quickjs/native/jni/promise_rejection_handler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "promise_rejection_handler.h" 3 | #include "jni_globals.h" 4 | #include "jni_globals_generated.h" 5 | #include "js_value_to_jobject.h" 6 | 7 | void promise_rejection_handler(JSContext *ctx, JSValue promise, 8 | JSValue reason, 9 | int is_handled, void *opaque) { 10 | JNIEnv *env = get_jni_env(); 11 | if (env == NULL) { 12 | return; 13 | } 14 | jobject host = (jobject) opaque; 15 | if (!is_handled) { 16 | (*env)->CallVoidMethod(env, host, 17 | method_quick_js_set_unhandled_promise_rejection(env), 18 | js_value_to_jobject(env, ctx, reason)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /quickjs/native/jni/promise_rejection_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_PROMISE_REJECTION_HANDLER_H 2 | #define QJS_KT_PROMISE_REJECTION_HANDLER_H 3 | 4 | #include "quickjs.h" 5 | 6 | void promise_rejection_handler(JSContext *ctx, JSValue promise, 7 | JSValue reason, 8 | int is_handled, void *opaque); 9 | 10 | #endif //QJS_KT_PROMISE_REJECTION_HANDLER_H 11 | -------------------------------------------------------------------------------- /quickjs/native/jni/quickjs_jni.h: -------------------------------------------------------------------------------- 1 | #ifndef QJS_KT_JNI_H 2 | #define QJS_KT_JNI_H 3 | 4 | #include 5 | #include "cvector.h" 6 | #include "quickjs.h" 7 | #include "jni.h" 8 | 9 | /** 10 | * Global objects for the wrapped runtime. 11 | */ 12 | typedef struct { 13 | /** 14 | * Some JS values, used by C functions. 15 | */ 16 | cvector_vector_type(JSValue)managed_js_values; 17 | /** 18 | * Defined JS objects, keep them to support nested define. 19 | */ 20 | cvector_vector_type(JSValue)defined_js_objects; 21 | /** 22 | * Promise resolve/reject functions. 23 | */ 24 | cvector_vector_type(JSValue)created_js_functions; 25 | /** 26 | * Global JNI refs. 27 | */ 28 | cvector_vector_type(jobject)global_object_refs; 29 | /** 30 | * Result promises of eval calls. 31 | */ 32 | JSValue *evaluate_result_promise; 33 | /** 34 | * The mutex which is used to protect the JS stack in a multi-threaded environment. 35 | * Scopes with a JS_UpdateStackTop() call are required to be locked. 36 | */ 37 | pthread_mutex_t js_mutex; 38 | } Globals; 39 | 40 | #endif //QJS_KT_JNI_H 41 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = . tests 3 | 4 | AM_CFLAGS = -Wall -DWIN32_LEAN_AND_MEAN 5 | ACLOCAL_AMFLAGS = -I m4 6 | 7 | lib_LTLIBRARIES = libwinpthread.la 8 | 9 | include_HEADERS = include/pthread.h include/sched.h include/semaphore.h include/pthread_unistd.h include/pthread_time.h include/pthread_compat.h include/pthread_signal.h 10 | libwinpthread_la_CPPFLAGS = -I$(srcdir)/include -DIN_WINPTHREAD -DWINPTHREAD_DBG=1 -D__USE_MINGW_ANSI_STDIO=0 11 | libwinpthread_la_LDFLAGS = -no-undefined -version-info 1:0:0 -L$(builddir)/fakelib -Wc,-no-pthread 12 | EXTRA_libwinpthread_la_DEPENDENCIES = fakelib/libgcc.a fakelib/libgcc_eh.a fakelib/libgcc_s.a 13 | libwinpthread_la_SOURCES = \ 14 | src/barrier.h src/cond.h src/misc.h src/mutex.h src/rwlock.h src/spinlock.h src/thread.h src/ref.h src/sem.h src/wpth_ver.h \ 15 | src/barrier.c src/cond.c src/misc.c src/mutex.c src/rwlock.c src/spinlock.c src/thread.c src/ref.c src/sem.c src/sched.c \ 16 | src/winpthread_internal.h src/clock.c src/nanosleep.c src/version.rc 17 | 18 | # Break circular dep on bootstrap 19 | noinst_LIBRARIES = fakelib/libgcc.a fakelib/libgcc_eh.a fakelib/libgcc_s.a 20 | fakelib_libgcc_a_SOURCES = src/libgcc/dll_dependency.S src/libgcc/dll_math.c 21 | fakelib_libgcc_s_a_SOURCES = 22 | fakelib_libgcc_eh_a_SOURCES = 23 | 24 | lib_LIBRARIES = 25 | 26 | if COPY_STATIC 27 | lib_LIBRARIES += libpthread.a 28 | libpthread_a_SOURCES = 29 | libpthread_a_DEPENDENCIES = libwinpthread.la 30 | #FIXME: Use cp kludge until a better method presents itself 31 | #libpthread_a_LIBADD = $(LT_OBJDIR)/libwinpthread.a 32 | libpthread_a_AR = cp -f $(LT_OBJDIR)/libwinpthread.a 33 | endif 34 | 35 | if COPY_SHARED 36 | lib_LIBRARIES += libpthread.dll.a 37 | libpthread_dll_a_SOURCES = 38 | libpthread_dll_a_DEPENDENCIES = libwinpthread.la 39 | #FIXME: Use cp kludge until a better method presents itself 40 | #libpthread_dll_a_LIBADD = $(LT_OBJDIR)/libwinpthread.dll.a 41 | libpthread_dll_a_AR = cp -f $(LT_OBJDIR)/libwinpthread.dll.a 42 | endif 43 | 44 | # Tell libtool how to use the resource compiler 45 | .rc.lo: 46 | $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ 47 | 48 | DISTCHECK_CONFIGURE_FLAGS = --host=$(host_triplet) 49 | 50 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/README: -------------------------------------------------------------------------------- 1 | The Winpthreads Library 2 | ----------------------- 3 | 4 | This library provides POSIX threading APIs for mingw-w64. 5 | 6 | For maximum compatibility, winpthreads headers expose APIs without the 7 | `dllimport` attribute by default. If your program is linked against the 8 | DLL, you may define the `WINPTHREADS_USE_DLLIMPORT` macro to add the 9 | `dllimport` attribute to all APIs, which makes function calls to them a 10 | bit more efficient. 11 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_DLFCN_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_INTTYPES_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_LIMITS_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_MEMORY_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_STDINT_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_STDLIB_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STRINGS_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STRING_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_SYS_STAT_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_SYS_TIMEB_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_SYS_TYPES_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_UNISTD_H 38 | 39 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 40 | #undef LT_OBJDIR 41 | 42 | /* Name of package */ 43 | #undef PACKAGE 44 | 45 | /* Define to the address where bug reports for this package should be sent. */ 46 | #undef PACKAGE_BUGREPORT 47 | 48 | /* Define to the full name of this package. */ 49 | #undef PACKAGE_NAME 50 | 51 | /* Define to the full name and version of this package. */ 52 | #undef PACKAGE_STRING 53 | 54 | /* Define to the one symbol short name of this package. */ 55 | #undef PACKAGE_TARNAME 56 | 57 | /* Define to the home page for this package. */ 58 | #undef PACKAGE_URL 59 | 60 | /* Define to the version of this package. */ 61 | #undef PACKAGE_VERSION 62 | 63 | /* Define to 1 if you have the ANSI C header files. */ 64 | #undef STDC_HEADERS 65 | 66 | /* Version number of package */ 67 | #undef VERSION 68 | 69 | /* Define to `__inline__' or `__inline' if that's what the C compiler 70 | calls it, or to nothing if 'inline' is not supported under any name. */ 71 | #ifndef __cplusplus 72 | #undef inline 73 | #endif 74 | 75 | /* Define to `unsigned int' if does not define. */ 76 | #undef size_t 77 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([mingw-w64-winpthreads], [1.0], [mingw-w64-public@lists.sf.net]) 6 | AC_CONFIG_AUX_DIR([build-aux]) 7 | AC_CONFIG_SRCDIR([src/spinlock.c]) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | 11 | AM_INIT_AUTOMAKE([foreign subdir-objects]) 12 | AM_MAINTAINER_MODE 13 | 14 | AC_CANONICAL_HOST 15 | 16 | # Checks for programs. 17 | AC_NO_EXECUTABLES 18 | AC_PROG_CC 19 | AC_PROG_RANLIB 20 | AM_PROG_AS 21 | AM_PROG_AR 22 | 23 | # Libtool 2.4 should check them correctly 24 | # AC_CHECK_TOOLS([AR],[ar],[:]) 25 | 26 | # Libtool 27 | LT_INIT([win32-dll]) 28 | LT_LANG([Windows Resource]) 29 | 30 | AC_SUBST([LT_OBJDIR],$lt_cv_objdir) 31 | 32 | AS_VAR_IF([enable_shared], [yes], [AS_VAR_SET([copy_shared])]) 33 | AS_VAR_IF([enable_static], [yes], [AS_VAR_SET([copy_static])]) 34 | AM_CONDITIONAL( [COPY_SHARED], [AS_VAR_TEST_SET([copy_shared])] ) 35 | AM_CONDITIONAL( [COPY_STATIC], [AS_VAR_TEST_SET([copy_static])] ) 36 | 37 | # Checks for libraries. 38 | # FIXME: Replace `main' with a function in `-lpthread': 39 | #AC_CHECK_LIB([pthread], [main]) 40 | 41 | # Checks for header files. 42 | AC_CHECK_HEADERS([limits.h sys/timeb.h]) 43 | 44 | # Checks for typedefs, structures, and compiler characteristics. 45 | AC_C_INLINE 46 | AC_TYPE_SIZE_T 47 | 48 | # Checks for library functions. 49 | #AC_FUNC_MALLOC 50 | #AC_FUNC_REALLOC 51 | # mingw-w64 should already have them 52 | #AC_CHECK_FUNCS([ftime gettimeofday memset]) 53 | 54 | AC_SUBST([RCFLAGS]) 55 | 56 | AC_CONFIG_FILES([Makefile tests/Makefile]) 57 | AC_OUTPUT 58 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/include/pthread_signal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_SIGNAL_H 24 | #define WIN_PTHREADS_SIGNAL_H 25 | 26 | /* Windows has rudimentary signals support. */ 27 | #define pthread_sigmask(H, S1, S2) 0 28 | 29 | #endif /* WIN_PTHREADS_SIGNAL_H */ 30 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 4179 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.6]) 16 | m4_define([LT_PACKAGE_REVISION], [2.4.6]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.6' 20 | macro_revision='2.4.6' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_BARRIER_H 24 | #define WIN_PTHREADS_BARRIER_H 25 | 26 | #define LIFE_BARRIER 0xBAB1FEED 27 | #define DEAD_BARRIER 0xDEADB00F 28 | 29 | #define _PTHREAD_BARRIER_FLAG (1<<30) 30 | 31 | #define CHECK_BARRIER(b) { \ 32 | if (!(b) || ( ((barrier_t *)(*b))->valid != (unsigned int)LIFE_BARRIER ) ) return EINVAL; } 33 | 34 | #include "../include/semaphore.h" 35 | 36 | typedef struct barrier_t barrier_t; 37 | struct barrier_t 38 | { 39 | int valid; 40 | int busy; 41 | int count; 42 | int total; 43 | int share; 44 | long sel; 45 | pthread_mutex_t m; 46 | sem_t sems[2]; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/libgcc/dll_dependency.S: -------------------------------------------------------------------------------- 1 | /* Implementation for gcc's internal stack-allocation routines. */ 2 | #if defined(__i386__) || defined(__x86_64__) 3 | .global ___chkstk 4 | .global __alloca 5 | 6 | .global ___chkstk_ms 7 | ___chkstk_ms: 8 | #ifdef _WIN64 9 | pushq %rax 10 | pushq %rcx 11 | cmpq $0x1000, %rax 12 | leaq 24(%rsp), %rcx 13 | jb .Lchkstk_ms_end 14 | .Lchkstk_ms_loop: 15 | subq $0x1000, %rcx 16 | subq $0x1000, %rax 17 | orq $0x0, (%rcx) 18 | cmpq $0x1000, %rax 19 | ja .Lchkstk_ms_loop 20 | .Lchkstk_ms_end: 21 | subq %rax, %rcx 22 | orq $0x0, (%rcx) 23 | popq %rcx 24 | popq %rax 25 | ret 26 | #else 27 | pushl %eax 28 | pushl %ecx 29 | cmpl $0x1000, %eax 30 | leal 12(%esp), %ecx 31 | jb chkstk_ms_end 32 | chkstk_ms_loop: 33 | subl $0x1000, %ecx 34 | subl $0x1000, %eax 35 | orl $0x0, (%ecx) 36 | cmpl $0x1000, %eax 37 | ja chkstk_ms_loop 38 | chkstk_ms_end: 39 | subl %eax, %ecx 40 | orl $0x0, (%ecx) 41 | popl %ecx 42 | popl %eax 43 | ret 44 | #endif 45 | 46 | #ifdef _WIN64 47 | __alloca: 48 | movq %rcx, %rax 49 | .align 4 50 | ___chkstk: 51 | popq %r11 52 | movq %rsp, %r10 53 | cmpq $0x1000, %rax 54 | jb .Lchkstk_end 55 | .Lchkstk_loop: 56 | subq $0x1000, %r10 57 | subq $0x1000, %rax 58 | orl $0x0, (%r10) 59 | cmpq $0x1000, %rax 60 | ja .Lchkstk_loop 61 | .Lchkstk_end: 62 | subq %rax, %r10 63 | movq %rsp, %rax 64 | orl $0x0, (%r10) 65 | movq %r10, %rsp 66 | pushq %r11 67 | ret 68 | #else 69 | ___chkstk: 70 | __alloca: 71 | pushl %ecx 72 | leal 8(%esp), %ecx 73 | cmpl $0x1000, %eax /* > 4k ?*/ 74 | jb chkstk_end 75 | chkstk_loop: 76 | subl $0x1000, %ecx 77 | subl $0x1000, %eax 78 | orl $0x0, (%ecx) 79 | cmpl $0x1000, %eax 80 | ja chkstk_loop 81 | chkstk_end: 82 | subl %eax, %ecx 83 | orl $0x0, (%ecx) 84 | movl %esp, %eax 85 | movl %ecx, %esp 86 | movl (%eax), %ecx 87 | pushl 4(%eax) 88 | ret 89 | #endif 90 | #endif 91 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/nanosleep.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file has no copyright assigned and is placed in the Public Domain. 3 | * This file is part of the w64 mingw-runtime package. 4 | * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "pthread.h" 11 | #include "pthread_time.h" 12 | #include "winpthread_internal.h" 13 | 14 | #define POW10_3 1000 15 | #define POW10_4 10000 16 | #define POW10_6 1000000 17 | #define POW10_9 1000000000 18 | #define MAX_SLEEP_IN_MS 4294967294UL 19 | 20 | /** 21 | * Sleep for the specified time. 22 | * @param request The desired amount of time to sleep. 23 | * @param remain The remain amount of time to sleep. 24 | * @return If the function succeeds, the return value is 0. 25 | * If the function fails, the return value is -1, 26 | * with errno set to indicate the error. 27 | */ 28 | int nanosleep(const struct timespec *request, struct timespec *remain) 29 | { 30 | unsigned long ms, rc = 0; 31 | unsigned __int64 u64, want, real; 32 | 33 | union { 34 | unsigned __int64 ns100; 35 | FILETIME ft; 36 | } _start, _end; 37 | 38 | if (request->tv_sec < 0 || request->tv_nsec < 0 || request->tv_nsec >= POW10_9) { 39 | errno = EINVAL; 40 | return -1; 41 | } 42 | 43 | if (remain != NULL) GetSystemTimeAsFileTime(&_start.ft); 44 | 45 | want = u64 = request->tv_sec * POW10_3 + request->tv_nsec / POW10_6; 46 | while (u64 > 0 && rc == 0) { 47 | if (u64 >= MAX_SLEEP_IN_MS) ms = MAX_SLEEP_IN_MS; 48 | else ms = (unsigned long) u64; 49 | 50 | u64 -= ms; 51 | rc = pthread_delay_np_ms(ms); 52 | } 53 | 54 | if (rc != 0) { /* WAIT_IO_COMPLETION (192) */ 55 | if (remain != NULL) { 56 | GetSystemTimeAsFileTime(&_end.ft); 57 | real = (_end.ns100 - _start.ns100) / POW10_4; 58 | 59 | if (real >= want) u64 = 0; 60 | else u64 = want - real; 61 | 62 | remain->tv_sec = u64 / POW10_3; 63 | remain->tv_nsec = (long) (u64 % POW10_3) * POW10_6; 64 | } 65 | 66 | errno = EINTR; 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/ref.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "semaphore.h" 28 | #include "rwlock.h" 29 | #include "cond.h" 30 | #include "barrier.h" 31 | #include "sem.h" 32 | #include "ref.h" 33 | #include "misc.h" 34 | 35 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/ref.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_REF_H 24 | #define WIN_PTHREADS_REF_H 25 | #include "pthread.h" 26 | #include "semaphore.h" 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/rwlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_RWLOCK_H 24 | #define WIN_PTHREADS_RWLOCK_H 25 | 26 | #define LIFE_RWLOCK 0xBAB1F0ED 27 | #define DEAD_RWLOCK 0xDEADB0EF 28 | 29 | #define INIT_RWLOCK(rwl) { int r; \ 30 | if (STATIC_RWL_INITIALIZER(*rwl)) { if ((r = rwlock_static_init(rwl))) { if (r != EBUSY) return r; }}} 31 | 32 | #define STATIC_RWL_INITIALIZER(x) ((pthread_rwlock_t)(x) == ((pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER)) 33 | 34 | typedef struct rwlock_t rwlock_t; 35 | struct rwlock_t { 36 | unsigned int valid; 37 | int busy; 38 | LONG nex_count; /* Exclusive access counter. */ 39 | LONG nsh_count; /* Shared access counter. */ 40 | LONG ncomplete; /* Shared completed counter. */ 41 | pthread_mutex_t mex; /* Exclusive access protection. */ 42 | pthread_mutex_t mcomplete; /* Shared completed protection. */ 43 | pthread_cond_t ccomplete; /* Shared access completed queue. */ 44 | }; 45 | 46 | #define RWL_SET 0x01 47 | #define RWL_TRY 0x02 48 | 49 | void rwl_print(volatile pthread_rwlock_t *rwl, char *txt); 50 | void rwl_print_set(int state); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/sem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_SEM 24 | #define WIN_SEM 25 | 26 | #include 27 | 28 | #define LIFE_SEM 0xBAB1F00D 29 | #define DEAD_SEM 0xDEADBEEF 30 | 31 | typedef struct _sem_t _sem_t; 32 | struct _sem_t 33 | { 34 | unsigned int valid; 35 | HANDLE s; 36 | volatile long value; 37 | pthread_mutex_t vlock; 38 | }; 39 | 40 | #endif /* WIN_SEM */ 41 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/winpthread_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WINPTHREAD_INTERNAL_H 24 | #define WINPTHREAD_INTERNAL_H 25 | struct _pthread_v * WINPTHREAD_API __pth_gpointer_locked (pthread_t id); 26 | int pthread_delay_np_ms (DWORD to); 27 | #endif /*WINPTHREAD_INTERNAL_H*/ 28 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/src/wpth_ver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2016 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef __WPTHREADS_VERSION__ 24 | #define __WPTHREADS_VERSION__ 25 | 26 | #define WPTH_VERSION 1,0,0,0 27 | #define WPTH_VERSION_STRING "1, 0, 0, 0\0" 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include 2 | AM_LDFLAGS = -L$(top_builddir)/fakelib -L$(top_builddir) -lwinpthread -static 3 | 4 | #FIXME: The test "test.c" is inherently broken currently. 5 | check_PROGRAMS = t_clock_getres t_clock_gettime t_clock_nanosleep t_clock_settime t_nanosleep #test 6 | TESTS = $(check_PROGRAMS) 7 | 8 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests/t_clock_getres.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define POW10_9 1000000000 7 | 8 | #define assert(_Expression) (void)( (!!(_Expression)) || (_my_assert(#_Expression, __FILE__, __LINE__), 0) ) 9 | 10 | static __inline void _my_assert(char *message, char *file, unsigned int line) 11 | { 12 | fprintf(stderr, "Assertion failed: %s , file %s, line %u\n", message, file, line); 13 | exit(1); 14 | } 15 | 16 | double sub_and_div(const struct timespec *t1, const struct timespec *t2, const struct timespec *r) 17 | { 18 | __int64 diff = (t2->tv_sec - t1->tv_sec) * POW10_9 + (t2->tv_nsec - t1->tv_nsec); 19 | return diff / (double) (r->tv_sec * POW10_9 + r->tv_nsec); 20 | } 21 | 22 | void test_clock_getres(char *name, int id) 23 | { 24 | int rc; 25 | double d; 26 | struct timespec tp, t1, t2; 27 | 28 | rc = clock_getres(id, &tp); 29 | assert(rc == 0); 30 | printf("%s resolution: %d.%09d sec\n", name, (int) tp.tv_sec, (int) tp.tv_nsec); 31 | 32 | rc = clock_gettime(id, &t1); 33 | assert(rc == 0); 34 | printf("%s time: %d.%09d sec\n", name, (int) t1.tv_sec, (int) t1.tv_nsec); 35 | 36 | if (id == CLOCK_REALTIME || id == CLOCK_MONOTONIC) { 37 | struct timespec request = {1, 0}; 38 | clock_nanosleep(CLOCK_REALTIME, 0, &request, NULL); 39 | } else { 40 | long i; 41 | for (i = 0; i < 100000000; i++) { 42 | rand(); 43 | } 44 | } 45 | 46 | rc = clock_gettime(id, &t2); 47 | assert(rc == 0); 48 | printf("%s time: %d.%09d sec\n", name, (int) t2.tv_sec, (int) t2.tv_nsec); 49 | 50 | d = sub_and_div(&t1, &t2, &tp); 51 | printf("sub_and_div: %7.3lf\n", d); 52 | printf("\n"); 53 | } 54 | 55 | int main(int argc, char *argv[]) 56 | { 57 | test_clock_getres(" CLOCK_REALTIME", CLOCK_REALTIME); 58 | test_clock_getres(" CLOCK_MONOTONIC", CLOCK_MONOTONIC); 59 | test_clock_getres("CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID); 60 | test_clock_getres(" CLOCK_THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests/t_clock_gettime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define assert(_Expression) (void)( (!!(_Expression)) || (_my_assert(#_Expression, __FILE__, __LINE__), 0) ) 8 | 9 | static __inline void _my_assert(char *message, char *file, unsigned int line) 10 | { 11 | fprintf(stderr, "Assertion failed: %s , file %s, line %u\n", message, file, line); 12 | exit(1); 13 | } 14 | 15 | void test_clock_gettime() 16 | { 17 | int rc; 18 | struct timespec tp, request = { 1, 0 }, remain; 19 | 20 | rc = clock_gettime(CLOCK_REALTIME, &tp); 21 | assert(rc == 0); 22 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 23 | 24 | rc = clock_gettime(CLOCK_MONOTONIC, &tp); 25 | assert(rc == 0); 26 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_MONOTONIC)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 27 | 28 | rc = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); 29 | assert(rc == 0); 30 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_PROCESS_CPUTIME_ID)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 31 | 32 | rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp); 33 | assert(rc == 0); 34 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_THREAD_CPUTIME_ID)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 35 | 36 | rc = clock_nanosleep(CLOCK_REALTIME, 0, &request, &remain); 37 | assert(rc == 0); 38 | 39 | rc = clock_gettime(CLOCK_REALTIME, &tp); 40 | assert(rc == 0); 41 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 42 | 43 | rc = clock_gettime(CLOCK_MONOTONIC, &tp); 44 | assert(rc == 0); 45 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_MONOTONIC)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 46 | 47 | rc = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); 48 | assert(rc == 0); 49 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_PROCESS_CPUTIME_ID)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 50 | 51 | rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp); 52 | assert(rc == 0); 53 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_THREAD_CPUTIME_ID)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 54 | 55 | } 56 | int main(int argc, char *argv[]) 57 | { 58 | test_clock_gettime(); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests/t_clock_nanosleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define assert(_Expression) (void)( (!!(_Expression)) || (_my_assert(#_Expression, __FILE__, __LINE__), 0) ) 9 | 10 | static __inline void _my_assert(char *message, char *file, unsigned int line) 11 | { 12 | fprintf(stderr, "Assertion failed: %s , file %s, line %u\n", message, file, line); 13 | exit(1); 14 | } 15 | 16 | void test_clock_nanosleep() 17 | { 18 | int rc; 19 | struct timespec tp, request = { 1, 0 }, remain; 20 | 21 | rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, &remain); 22 | assert(rc == -1 && errno == EINVAL); 23 | 24 | rc = clock_nanosleep(CLOCK_PROCESS_CPUTIME_ID, 0, &request, &remain); 25 | assert(rc == -1 && errno == EINVAL); 26 | 27 | rc = clock_nanosleep(CLOCK_THREAD_CPUTIME_ID, 0, &request, &remain); 28 | assert(rc == -1 && errno == EINVAL); 29 | 30 | rc = clock_gettime(CLOCK_REALTIME, &tp); 31 | assert(rc == 0); 32 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 33 | 34 | rc = clock_nanosleep(CLOCK_REALTIME, 0, &request, &remain); 35 | assert(rc == 0); 36 | 37 | rc = clock_gettime(CLOCK_REALTIME, &tp); 38 | assert(rc == 0); 39 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 40 | 41 | request.tv_sec = tp.tv_sec + 1; 42 | request.tv_nsec = 0; 43 | 44 | rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &request, &remain); 45 | assert(rc == 0); 46 | 47 | rc = clock_gettime(CLOCK_REALTIME, &tp); 48 | assert(rc == 0); 49 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 50 | } 51 | 52 | int main(int argc, char *argv[]) 53 | { 54 | test_clock_nanosleep(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests/t_clock_settime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define assert(_Expression) (void)( (!!(_Expression)) || (_my_assert(#_Expression, __FILE__, __LINE__), 0) ) 9 | 10 | static __inline void _my_assert(char *message, char *file, unsigned int line) 11 | { 12 | fprintf(stderr, "Assertion failed: %s , file %s, line %u\n", message, file, line); 13 | exit(1); 14 | } 15 | 16 | void test_clock_settime() 17 | { 18 | int rc; 19 | struct timespec tp, request = { 1, 0 }, remain; 20 | 21 | rc = clock_gettime(CLOCK_REALTIME, &tp); 22 | assert(rc == 0); 23 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 24 | 25 | rc = clock_settime(CLOCK_MONOTONIC, &tp); 26 | assert(rc == -1 && (errno == EINVAL)); 27 | 28 | rc = clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tp); 29 | assert(rc == -1 && (errno == EINVAL)); 30 | 31 | rc = clock_settime(CLOCK_THREAD_CPUTIME_ID, &tp); 32 | assert(rc == -1 && (errno == EINVAL)); 33 | 34 | rc = clock_settime(CLOCK_REALTIME, &tp); 35 | assert(rc == 0 || (errno == EPERM)); 36 | 37 | rc = clock_gettime(CLOCK_REALTIME, &tp); 38 | assert(rc == 0); 39 | printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec); 40 | } 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | test_clock_settime(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/ChangeLog: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/ChangeLog.2013: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/quickjs/native/winpthreads/tests_pthread/ChangeLog.2013 -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/Debug.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "Debug"=.\Debug.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/Debug.plg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
 4 | 

Build Log

5 |

6 | --------------------Configuration: Debug - Win32 Debug-------------------- 7 |

8 |

Command Lines

9 | Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP9.tmp" with contents 10 | [ 11 | /nologo /MDd /W3 /WX /Gm /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "CLEANUP_C" /FR"Debug/" /Fp"Debug/Debug.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 12 | "E:\PTHREADS\pthreads.2\tests\semaphore1.c" 13 | ] 14 | Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP9.tmp" 15 | Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPA.tmp" with contents 16 | [ 17 | kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib pthreadVC2d.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/Debug.pdb" /debug /machine:I386 /out:"Debug/Debug.exe" /pdbtype:sept /libpath:".." 18 | .\Debug\semaphore1.obj 19 | ] 20 | Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPA.tmp" 21 |

Output Window

22 | Compiling... 23 | semaphore1.c 24 | Linking... 25 | 26 | 27 | 28 |

Results

29 | Debug.exe - 0 error(s), 0 warning(s) 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/Debug.txt: -------------------------------------------------------------------------------- 1 | This project is used to debug individual test case programs. 2 | 3 | To build and debug a test case: 4 | - add the .c file to this project; 5 | - remove any .c files from other test cases from this project. 6 | - build and debug as usual. -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/README: -------------------------------------------------------------------------------- 1 | Running test cases in this directory 2 | ------------------------------------ 3 | 4 | These make scripts expect to be able to copy the dll, library 5 | and header files from this directory's parent directory, 6 | which should be the pthreads-win32 source directory. 7 | 8 | MS VC nmake 9 | ------------- 10 | 11 | Run the target corresponding to the DLL version being tested: 12 | 13 | nmake clean VC 14 | 15 | or: 16 | 17 | nmake clean VS 18 | 19 | 20 | GNU GCC make 21 | ------------ 22 | 23 | Run "make clean" and then "make". See the "Known bugs" section 24 | in ..\README. 25 | 26 | 27 | Writing Test Cases 28 | ------------------ 29 | 30 | Tests written in this test suite should behave in the following manner: 31 | 32 | * If a test fails, leave main() with a result of 1. 33 | 34 | * If a test succeeds, leave main() with a result of 0. 35 | 36 | * No diagnostic output should appear when the test is succeeding. 37 | Diagnostic output may be emitted if something in the test 38 | fails, to help determine the cause of the test failure. 39 | 40 | Notes: 41 | ------ 42 | 43 | Many test cases use knowledge of implementation internals which are supposed 44 | to be opaque to portable applications. 45 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/SIZES.GC: -------------------------------------------------------------------------------- 1 | Sizes of winpthreads structs 2 | ------------------------------- 3 | pthread_t 8 4 | pthread_attr_t_ 32 5 | pthread_mutex_t_ 32 6 | pthread_mutexattr_t_ 4 7 | pthread_barrier_t_ 48 8 | pthread_barrierattr_t_ 8 9 | pthread_key_t_ 4 10 | pthread_cond_t_ 176 11 | pthread_condattr_t_ 4 12 | pthread_rwlock_t_ 48 13 | pthread_rwlockattr_t_ 4 14 | pthread_once_t_ 4 15 | sched_param 4 16 | ------------------------------- 17 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/SIZES.GCE: -------------------------------------------------------------------------------- 1 | Sizes of pthreads-win32 structs 2 | ------------------------------- 3 | pthread_t 8 4 | ptw32_thread_t 76 5 | pthread_attr_t_ 28 6 | sem_t_ 12 7 | pthread_mutex_t_ 24 8 | pthread_mutexattr_t_ 8 9 | pthread_spinlock_t_ 8 10 | pthread_barrier_t_ 36 11 | pthread_barrierattr_t_ 4 12 | pthread_key_t_ 16 13 | pthread_cond_t_ 32 14 | pthread_condattr_t_ 4 15 | pthread_rwlock_t_ 28 16 | pthread_rwlockattr_t_ 4 17 | pthread_once_t_ 16 18 | ptw32_cleanup_t 12 19 | ptw32_mcs_node_t_ 16 20 | sched_param 4 21 | ------------------------------- 22 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/SIZES.VC: -------------------------------------------------------------------------------- 1 | Sizes of pthreads-win32 structs 2 | ------------------------------- 3 | pthread_t_ 124 4 | pthread_attr_t_ 28 5 | sem_t_ 4 6 | pthread_mutex_t_ 44 7 | pthread_mutexattr_t_ 8 8 | pthread_spinlock_t_ 8 9 | pthread_barrier_t_ 24 10 | pthread_barrierattr_t_ 4 11 | pthread_key_t_ 16 12 | pthread_cond_t_ 32 13 | pthread_condattr_t_ 4 14 | pthread_rwlock_t_ 28 15 | pthread_rwlockattr_t_ 4 16 | pthread_once_t_ 8 17 | ptw32_cleanup_t 12 18 | sched_param 4 19 | ------------------------------- 20 | 21 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/SIZES.VCE: -------------------------------------------------------------------------------- 1 | Sizes of pthreads-win32 structs 2 | ------------------------------- 3 | pthread_t_ 68 4 | pthread_attr_t_ 28 5 | sem_t_ 4 6 | pthread_mutex_t_ 44 7 | pthread_mutexattr_t_ 8 8 | pthread_spinlock_t_ 8 9 | pthread_barrier_t_ 24 10 | pthread_barrierattr_t_ 4 11 | pthread_key_t_ 16 12 | pthread_cond_t_ 32 13 | pthread_condattr_t_ 4 14 | pthread_rwlock_t_ 28 15 | pthread_rwlockattr_t_ 4 16 | pthread_once_t_ 8 17 | ptw32_cleanup_t 12 18 | sched_param 4 19 | ------------------------------- 20 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/SIZES.VSE: -------------------------------------------------------------------------------- 1 | Sizes of pthreads-win32 structs 2 | ------------------------------- 3 | pthread_t_ 68 4 | pthread_attr_t_ 28 5 | sem_t_ 4 6 | pthread_mutex_t_ 44 7 | pthread_mutexattr_t_ 8 8 | pthread_spinlock_t_ 8 9 | pthread_barrier_t_ 24 10 | pthread_barrierattr_t_ 4 11 | pthread_key_t_ 16 12 | pthread_cond_t_ 32 13 | pthread_condattr_t_ 4 14 | pthread_rwlock_t_ 28 15 | pthread_rwlockattr_t_ 4 16 | pthread_once_t_ 8 17 | ptw32_cleanup_t 12 18 | sched_param 4 19 | ------------------------------- 20 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/barrier1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * barrier1.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Create a barrier object and then destroy it. 37 | * 38 | */ 39 | 40 | #include "test.h" 41 | 42 | pthread_barrier_t barrier = NULL; 43 | 44 | int 45 | main() 46 | { 47 | assert(barrier == NULL); 48 | 49 | assert(pthread_barrier_init(&barrier, NULL, 1) == 0); 50 | 51 | assert(barrier != NULL); 52 | 53 | assert(pthread_barrier_destroy(&barrier) == 0); 54 | 55 | assert(barrier == NULL); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/barrier2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * barrier2.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Declare a single barrier object, wait on it, 37 | * and then destroy it. 38 | * 39 | */ 40 | 41 | #include "test.h" 42 | 43 | pthread_barrier_t barrier = NULL; 44 | 45 | int 46 | main() 47 | { 48 | assert(pthread_barrier_init(&barrier, NULL, 1) == 0); 49 | 50 | assert(pthread_barrier_wait(&barrier) == PTHREAD_BARRIER_SERIAL_THREAD); 51 | 52 | assert(pthread_barrier_destroy(&barrier) == 0); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/condvar2_1.c: -------------------------------------------------------------------------------- 1 | #define _WIN32_WINNT 0x400 2 | 3 | #include "test.h" 4 | #include 5 | 6 | static pthread_cond_t cv; 7 | static pthread_mutex_t mutex; 8 | static struct timespec abstime = { 0, 0 }; 9 | 10 | enum { 11 | NUMTHREADS = 30 12 | }; 13 | 14 | void * 15 | mythread(void * arg) 16 | { 17 | assert(pthread_mutex_lock(&mutex) == 0); 18 | 19 | assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT); 20 | 21 | assert(pthread_mutex_unlock(&mutex) == 0); 22 | 23 | return arg; 24 | } 25 | 26 | 27 | 28 | int 29 | main() 30 | { 31 | int i; 32 | pthread_t t[NUMTHREADS + 1]; 33 | intptr_t result = 0; 34 | struct _timeb currSysTime; 35 | const DWORD NANOSEC_PER_MILLISEC = 1000000; 36 | 37 | assert(pthread_cond_init(&cv, NULL) == 0); 38 | 39 | assert(pthread_mutex_init(&mutex, NULL) == 0); 40 | 41 | /* get current system time */ 42 | _ftime(&currSysTime); 43 | 44 | abstime.tv_sec = currSysTime.time; 45 | abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; 46 | 47 | abstime.tv_sec += 5; 48 | 49 | assert(pthread_mutex_lock(&mutex) == 0); 50 | 51 | for (i = 1; i <= NUMTHREADS; i++) 52 | { 53 | assert(pthread_create(&t[i], NULL, mythread, ((void *) (size_t) i)) == 0); 54 | } 55 | 56 | assert(pthread_mutex_unlock(&mutex) == 0); 57 | 58 | for (i = 1; i <= NUMTHREADS; i++) 59 | { 60 | assert(pthread_join(t[i], (void **) &result) == 0); 61 | assert((int)result == i); 62 | } 63 | 64 | { 65 | int result = pthread_cond_destroy(&cv); 66 | if (result != 0) 67 | { 68 | fprintf(stderr, "Result = %s\n", error_string[result]); 69 | #if 0 70 | fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); 71 | fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); 72 | fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); 73 | #endif 74 | fflush(stderr); 75 | } 76 | assert(result == 0); 77 | } 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/condvar3.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | 4 | static pthread_cond_t cv; 5 | static pthread_mutex_t mutex; 6 | static int shared = 0; 7 | 8 | enum { 9 | NUMTHREADS = 2 /* Including the primary thread. */ 10 | }; 11 | 12 | void * 13 | mythread(void * arg) 14 | { 15 | int result = 0; 16 | 17 | assert(pthread_mutex_lock(&mutex) == 0); 18 | shared++; 19 | assert(pthread_mutex_unlock(&mutex) == 0); 20 | 21 | if ((result = pthread_cond_signal(&cv)) != 0) 22 | { 23 | printf("Error = %s\n", error_string[result]); 24 | } 25 | assert(result == 0); 26 | 27 | 28 | return (void *) 0; 29 | } 30 | 31 | int 32 | main() 33 | { 34 | pthread_t t[NUMTHREADS]; 35 | struct timespec abstime = { 0, 0 }; 36 | struct _timeb currSysTime; 37 | const DWORD NANOSEC_PER_MILLISEC = 1000000; 38 | 39 | assert((t[0] = pthread_self()) != 0); 40 | assert(pthread_gethandle (t[0]) != NULL); 41 | 42 | assert(pthread_cond_init(&cv, NULL) == 0); 43 | 44 | assert(pthread_mutex_init(&mutex, NULL) == 0); 45 | 46 | assert(pthread_mutex_lock(&mutex) == 0); 47 | 48 | /* get current system time */ 49 | _ftime(&currSysTime); 50 | 51 | abstime.tv_sec = currSysTime.time; 52 | abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; 53 | 54 | assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); 55 | 56 | abstime.tv_sec += 5; 57 | 58 | while (! (shared > 0)) 59 | assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == 0); 60 | 61 | assert(shared > 0); 62 | 63 | assert(pthread_mutex_unlock(&mutex) == 0); 64 | 65 | assert(pthread_join(t[1], NULL) == 0); 66 | 67 | assert(pthread_cond_destroy(&cv) == 0); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/context1.c: -------------------------------------------------------------------------------- 1 | #define _WIN32_WINNT 0x400 2 | 3 | #include "test.h" 4 | 5 | static int washere = 0; 6 | 7 | static void * func(void * arg) 8 | { 9 | washere = 1; 10 | 11 | Sleep(1000); 12 | 13 | return 0; 14 | } 15 | 16 | static void 17 | anotherEnding () 18 | { 19 | /* 20 | * Switched context 21 | */ 22 | washere++; 23 | 24 | pthread_exit(0); 25 | } 26 | 27 | int 28 | main() 29 | { 30 | pthread_t t; 31 | HANDLE hThread; 32 | 33 | assert(pthread_create(&t, NULL, func, NULL) == 0); 34 | 35 | hThread = pthread_gethandle (t); 36 | 37 | Sleep(500); 38 | 39 | SuspendThread(hThread); 40 | 41 | if (WaitForSingleObject(hThread, 0) == WAIT_TIMEOUT) 42 | { 43 | /* 44 | * Ok, thread did not exit before we got to it. 45 | */ 46 | CONTEXT context; 47 | 48 | context.ContextFlags = CONTEXT_CONTROL; 49 | 50 | GetThreadContext(hThread, &context); 51 | #ifdef _M_X64 52 | context.Rip = (uintptr_t) anotherEnding; 53 | #else 54 | context.Eip = (uintptr_t) anotherEnding; 55 | #endif 56 | 57 | SetThreadContext(hThread, &context); 58 | ResumeThread(hThread); 59 | } 60 | else 61 | { 62 | printf("Exited early\n"); 63 | fflush(stdout); 64 | } 65 | 66 | Sleep(1000); 67 | 68 | assert(washere == 2); 69 | 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/create1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * create1.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Description: 37 | * Create a thread and check that it ran. 38 | * 39 | * Depends on API functions: None. 40 | */ 41 | 42 | #include "test.h" 43 | 44 | static int washere = 0; 45 | 46 | void * func(void * arg) 47 | { 48 | washere = 1; 49 | return 0; 50 | } 51 | 52 | int 53 | main() 54 | { 55 | pthread_t t; 56 | 57 | assert(pthread_create(&t, NULL, func, NULL) == 0); 58 | 59 | /* A dirty hack, but we cannot rely on pthread_join in this 60 | primitive test. */ 61 | Sleep(2000); 62 | 63 | assert(washere == 1); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/delay1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * delay1.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Depends on API functions: 37 | * pthread_delay_np 38 | */ 39 | 40 | #include "test.h" 41 | 42 | int 43 | main(int argc, char * argv[]) 44 | { 45 | struct timespec interval = {1L, 500000000L}; 46 | 47 | assert(pthread_delay_np(&interval) == 0); 48 | 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/equal1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test for pthread_equal. 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Depends on functions: pthread_create(). 37 | */ 38 | 39 | #include "test.h" 40 | 41 | void * func(void * arg) 42 | { 43 | Sleep(2000); 44 | return 0; 45 | } 46 | 47 | int 48 | main() 49 | { 50 | pthread_t t1, t2; 51 | 52 | assert(pthread_create(&t1, NULL, func, (void *) 1) == 0); 53 | 54 | assert(pthread_create(&t2, NULL, func, (void *) 2) == 0); 55 | 56 | assert(pthread_equal(t1, t2) == 0); 57 | 58 | assert(pthread_equal(t1,t1) != 0); 59 | 60 | /* This is a hack. We don't want to rely on pthread_join 61 | yet if we can help it. */ 62 | Sleep(4000); 63 | 64 | /* Success. */ 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/exit1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test for pthread_exit(). 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Depends on API functions: None. 37 | */ 38 | 39 | #include "test.h" 40 | 41 | int 42 | main(int argc, char * argv[]) 43 | { 44 | /* A simple test first. */ 45 | pthread_exit((void *) NULL); 46 | 47 | /* Not reached */ 48 | assert(0); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/exit2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test for pthread_exit(). 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Depends on API functions: 37 | * pthread_create() 38 | * pthread_exit() 39 | */ 40 | 41 | #include "test.h" 42 | 43 | void * 44 | func(void * arg) 45 | { 46 | pthread_exit(arg); 47 | 48 | /* Never reached. */ 49 | assert(0); 50 | 51 | return NULL; 52 | } 53 | 54 | int 55 | main(int argc, char * argv[]) 56 | { 57 | pthread_t t; 58 | 59 | assert(pthread_create(&t, NULL, func, (void *) NULL) == 0); 60 | 61 | Sleep(1000); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/exit3.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | void * 4 | func(void * arg) 5 | { 6 | pthread_exit(arg); 7 | 8 | /* Never reached. */ 9 | assert(0); 10 | 11 | return NULL; 12 | } 13 | 14 | int 15 | main(int argc, char * argv[]) 16 | { 17 | pthread_t id[4]; 18 | int i; 19 | 20 | /* Create a few threads and then exit. */ 21 | for (i = 0; i < 4; i++) 22 | { 23 | assert(pthread_create(&id[i], NULL, func, ((void *) (size_t) i)) == 0); 24 | } 25 | 26 | Sleep(1000); 27 | 28 | /* Success. */ 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/join0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test for pthread_join(). 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Depends on API functions: pthread_create(), pthread_exit(). 37 | */ 38 | 39 | #include "test.h" 40 | 41 | void * 42 | func(void * arg) 43 | { 44 | Sleep(2000); 45 | 46 | pthread_exit(arg); 47 | 48 | /* Never reached. */ 49 | exit(1); 50 | } 51 | 52 | int 53 | main(int argc, char * argv[]) 54 | { 55 | pthread_t id; 56 | intptr_t result = 0; 57 | 58 | /* Create a single thread and wait for it to exit. */ 59 | assert(pthread_create(&id, NULL, func, (void *) 123) == 0); 60 | 61 | assert(pthread_join(id, (void **) &result) == 0); 62 | 63 | assert(result == 123); 64 | 65 | /* Success. */ 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/join2.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | void * 4 | func(void * arg) 5 | { 6 | Sleep(1000); 7 | return arg; 8 | } 9 | 10 | int 11 | main(int argc, char * argv[]) 12 | { 13 | pthread_t id[4]; 14 | int i; 15 | intptr_t result = 0; 16 | 17 | /* Create a few threads and then exit. */ 18 | for (i = 0; i < 4; i++) 19 | { 20 | assert(pthread_create(&id[i], NULL, func, ((void *) (size_t) i)) == 0); 21 | } 22 | 23 | for (i = 0; i < 4; i++) 24 | { 25 | assert(pthread_join(id[i], (void **) &result) == 0); 26 | assert((int) result == i); 27 | } 28 | 29 | /* Success. */ 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/mutex2e.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mutex2e.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Declare a static mutex object, lock it, 37 | * and then unlock it again. 38 | * 39 | * Depends on API functions: 40 | * pthread_mutex_lock() 41 | * pthread_mutex_unlock() 42 | */ 43 | 44 | #include "test.h" 45 | 46 | pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER; 47 | 48 | int 49 | main() 50 | { 51 | assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); 52 | 53 | assert(pthread_mutex_lock(&mutex) == 0); 54 | 55 | assert(mutex != PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); 56 | 57 | assert(mutex != NULL); 58 | 59 | assert(pthread_mutex_unlock(&mutex) == 0); 60 | 61 | assert(pthread_mutex_destroy(&mutex) == 0); 62 | 63 | assert(mutex == NULL); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/mutex2r.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mutex2r.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Declare a static mutex object, lock it, 37 | * and then unlock it again. 38 | * 39 | * Depends on API functions: 40 | * pthread_mutex_lock() 41 | * pthread_mutex_unlock() 42 | */ 43 | 44 | #include "test.h" 45 | 46 | pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; 47 | 48 | int 49 | main() 50 | { 51 | assert(mutex == PTHREAD_RECURSIVE_MUTEX_INITIALIZER); 52 | 53 | assert(pthread_mutex_lock(&mutex) == 0); 54 | 55 | assert(mutex != PTHREAD_RECURSIVE_MUTEX_INITIALIZER); 56 | 57 | assert(mutex != NULL); 58 | 59 | assert(pthread_mutex_unlock(&mutex) == 0); 60 | 61 | assert(pthread_mutex_destroy(&mutex) == 0); 62 | 63 | assert(mutex == NULL); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/reuse1.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | enum { 4 | NUMTHREADS = 100 5 | }; 6 | 7 | static int washere = 0; 8 | 9 | void * func(void * arg) 10 | { 11 | washere = 1; 12 | return arg; 13 | } 14 | 15 | int 16 | main() 17 | { 18 | pthread_t t, last_t; 19 | void *tp, *last_tp; 20 | pthread_attr_t attr; 21 | void * result = NULL; 22 | int i; 23 | 24 | assert(pthread_attr_init(&attr) == 0);; 25 | assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); 26 | 27 | washere = 0; 28 | assert(pthread_create(&t, &attr, func, NULL) == 0); 29 | assert(pthread_join(t, &result) == 0);; 30 | assert(result == NULL); 31 | assert(washere == 1); 32 | last_t = t; 33 | last_tp = __pth_gpointer_locked (t); 34 | 35 | for (i = 1; i < NUMTHREADS; i++) 36 | { 37 | washere = 0; 38 | assert(pthread_create(&t, &attr, func, (void *) (intptr_t) i) == 0); 39 | pthread_join(t, &result); 40 | assert((intptr_t) result == (intptr_t) i); 41 | assert(washere == 1); 42 | /* thread IDs should be unique */ 43 | assert(!pthread_equal(t, last_t)); 44 | /* thread struct pointers should be the same */ 45 | tp = __pth_gpointer_locked(t); 46 | assert(tp == last_tp); 47 | last_t = t; 48 | last_tp = tp; 49 | } 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/reuse2.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | enum { 4 | NUMTHREADS = 10000 5 | }; 6 | 7 | 8 | static long done = 0; 9 | 10 | void * func(void * arg) 11 | { 12 | sched_yield(); 13 | 14 | InterlockedIncrement(&done); 15 | 16 | return (void *) 0; 17 | } 18 | 19 | int 20 | main() 21 | { 22 | pthread_t t[NUMTHREADS]; 23 | pthread_attr_t attr; 24 | int i; 25 | unsigned int notUnique = 0, 26 | totalHandles = 0, 27 | reuseMax = 0, 28 | reuseMin = NUMTHREADS; 29 | 30 | assert(pthread_attr_init(&attr) == 0); 31 | assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); 32 | 33 | for (i = 0; i < NUMTHREADS; i++) 34 | { 35 | assert(pthread_create(&t[i], &attr, func, NULL) == 0); 36 | } 37 | 38 | while (NUMTHREADS > InterlockedExchangeAdd((LPLONG)&done, 0L)) 39 | Sleep(100); 40 | 41 | Sleep(100); 42 | 43 | /* 44 | * Analyse reuse by computing min and max number of times pthread_create() 45 | * returned the same pthread_t value. 46 | */ 47 | for (i = 0; i < NUMTHREADS; i++) 48 | { 49 | if (t[i]) 50 | { 51 | unsigned int j, thisMax; 52 | 53 | thisMax = t[i]; 54 | 55 | for (j = i+1; j < NUMTHREADS; j++) 56 | if (__pth_gpointer_locked (t[i]) == __pth_gpointer_locked (t[j])) 57 | { 58 | if (t[i] == t[j]) 59 | notUnique++; 60 | if (thisMax < t[j]) 61 | thisMax = t[j]; 62 | t[j] = 0; 63 | } 64 | 65 | if (reuseMin > thisMax) 66 | reuseMin = thisMax; 67 | 68 | if (reuseMax < thisMax) 69 | reuseMax = thisMax; 70 | } 71 | } 72 | 73 | for (i = 0; i < NUMTHREADS; i++) 74 | if (t[i] != 0) 75 | totalHandles++; 76 | 77 | /* 78 | * pthread_t reuse counts start at 0, so we need to add 1 79 | * to the max and min values derived above. 80 | */ 81 | printf("For %d total threads:\n", NUMTHREADS); 82 | printf("Non-unique IDs = %d\n", notUnique); 83 | printf("Reuse maximum = %d\n", reuseMax + 1); 84 | printf("Reuse minimum = %d\n", reuseMin + 1); 85 | printf("Total handles = %d\n", totalHandles); 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/runall.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main(int argc, char * argv[]) 8 | { 9 | char b[100]; 10 | char fexe[100]; 11 | char fpass[100]; 12 | char ffail[100]; 13 | char fres[100]; 14 | char fnob[100]; 15 | char cmd[100]; 16 | char *e; 17 | struct stat st; 18 | DIR *dir; 19 | struct dirent *ent; 20 | 21 | if (argc!=2) { 22 | printf("usage: runall \n"); 23 | return 0; //EXIT_FAILURE; 24 | } 25 | dir = opendir (argv[1]); 26 | if (dir != NULL) { 27 | while ((ent = readdir (dir)) != NULL) { 28 | strcpy(b, ent->d_name); 29 | if (strstr(b,"runall.c")) { 30 | /* skip myself */ 31 | continue; 32 | } 33 | e = strchr(b,'.'); 34 | if (e) { 35 | *e ++ = '\0'; 36 | if (strcmp(e,"c")==0) { 37 | sprintf(fexe,"%s.exe",b); 38 | sprintf(fpass,"%s.pass",b); 39 | sprintf(ffail,"%s.fail",b); 40 | sprintf(fres,"%s.res",b); 41 | sprintf(fnob,"%s.x",b); 42 | 43 | if (stat(fexe,&st)==0) { 44 | if ( (stat(fpass,&st)!=0) && (stat(ffail,&st)!=0)) { 45 | sprintf(cmd,"%s 2> %s",fexe,fres); 46 | if (system(cmd)) { 47 | rename(fres,ffail); 48 | } else { 49 | rename(fres,fpass); 50 | } 51 | } 52 | } else { 53 | sprintf(cmd,"touch %s",fnob); 54 | system(cmd); 55 | } 56 | } 57 | } 58 | 59 | } 60 | closedir (dir); 61 | } else { 62 | /* could not open directory */ 63 | perror (""); 64 | return 0; //EXIT_FAILURE; 65 | } 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/rwlock1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rwlock1.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Create a simple rwlock object and then destroy it. 37 | * 38 | * Depends on API functions: 39 | * pthread_rwlock_init() 40 | * pthread_rwlock_destroy() 41 | */ 42 | 43 | #include "test.h" 44 | 45 | pthread_rwlock_t rwlock = NULL; 46 | 47 | int 48 | main() 49 | { 50 | assert(rwlock == NULL); 51 | 52 | assert(pthread_rwlock_init(&rwlock, NULL) == 0); 53 | 54 | assert(rwlock != NULL); 55 | 56 | assert(pthread_rwlock_destroy(&rwlock) == 0); 57 | 58 | assert(rwlock == NULL); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/rwlock2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rwlock2.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Declare a static rwlock object, lock it, 37 | * and then unlock it again. 38 | * 39 | * Depends on API functions: 40 | * pthread_rwlock_rdlock() 41 | * pthread_rwlock_unlock() 42 | */ 43 | 44 | #include "test.h" 45 | 46 | pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 47 | 48 | int 49 | main() 50 | { 51 | assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); 52 | 53 | assert(pthread_rwlock_rdlock(&rwlock) == 0); 54 | 55 | assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); 56 | 57 | assert(rwlock != NULL); 58 | 59 | assert(pthread_rwlock_unlock(&rwlock) == 0); 60 | 61 | assert(pthread_rwlock_destroy(&rwlock) == 0); 62 | 63 | assert(rwlock == NULL); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/self1.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | 4 | 5 | int 6 | main(int argc, char * argv[]) 7 | { 8 | assert(pthread_gethandle (pthread_self()) != NULL); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/self2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * self2.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Test for pthread_self(). 37 | * 38 | * Depends on API functions: 39 | * pthread_create() 40 | * pthread_self() 41 | * 42 | * Implicitly depends on: 43 | * pthread_getspecific() 44 | * pthread_setspecific() 45 | */ 46 | 47 | #include "test.h" 48 | #include 49 | 50 | static pthread_t me; 51 | 52 | void * 53 | entry(void * arg) 54 | { 55 | me = pthread_self(); 56 | 57 | return arg; 58 | } 59 | 60 | int 61 | main() 62 | { 63 | pthread_t t; 64 | 65 | assert(pthread_create(&t, NULL, entry, NULL) == 0); 66 | 67 | Sleep(100); 68 | 69 | assert(pthread_equal(t, me) != 0); 70 | 71 | /* Success. */ 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/sizes.c: -------------------------------------------------------------------------------- 1 | #define _WIN32_WINNT 0x400 2 | 3 | #include 4 | #include "test.h" 5 | 6 | int 7 | main() 8 | { 9 | printf("Sizes of winpthreads structs\n"); 10 | printf("-------------------------------\n"); 11 | printf("%30s %4" PRIdPTR "\n", "pthread_t", sizeof(pthread_t)); 12 | printf("%30s %4" PRIdPTR "\n", "pthread_attr_t_", sizeof(pthread_attr_t)); 13 | /* printf("%30s %4" PRIdPTR "\n", "sem_t_", sizeof(struct sem_t_)); */ 14 | printf("%30s %4" PRIdPTR "\n", "pthread_mutex_t_", sizeof(mutex_t)); 15 | printf("%30s %4" PRIdPTR "\n", "pthread_mutexattr_t_", sizeof(pthread_mutexattr_t)); 16 | printf("%30s %4" PRIdPTR "\n", "pthread_barrier_t_", sizeof(barrier_t)); 17 | printf("%30s %4" PRIdPTR "\n", "pthread_barrierattr_t_", sizeof(pthread_barrierattr_t)); 18 | printf("%30s %4" PRIdPTR "\n", "pthread_key_t_", sizeof(pthread_key_t)); 19 | printf("%30s %4" PRIdPTR "\n", "pthread_cond_t_", sizeof(cond_t)); 20 | printf("%30s %4" PRIdPTR "\n", "pthread_condattr_t_", sizeof(pthread_condattr_t)); 21 | printf("%30s %4" PRIdPTR "\n", "pthread_rwlock_t_", sizeof(rwlock_t)); 22 | printf("%30s %4" PRIdPTR "\n", "pthread_rwlockattr_t_", sizeof(pthread_rwlockattr_t)); 23 | printf("%30s %4" PRIdPTR "\n", "pthread_once_t_", sizeof(pthread_once_t)); 24 | /* printf("%30s %4" PRIdPTR "\n", "ptw32_cleanup_t", sizeof(struct ptw32_cleanup_t)); */ 25 | /* printf("%30s %4" PRIdPTR "\n", "ptw32_mcs_node_t_", sizeof(struct ptw32_mcs_node_t_)); */ 26 | printf("%30s %4" PRIdPTR "\n", "sched_param", sizeof(struct sched_param)); 27 | printf("-------------------------------\n"); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /quickjs/native/winpthreads/tests_pthread/spin1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * spin1.c 3 | * 4 | * 5 | * -------------------------------------------------------------------------- 6 | * 7 | * Pthreads-win32 - POSIX Threads Library for Win32 8 | * Copyright(C) 1998 John E. Bossom 9 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 10 | * 11 | * Contact Email: rpj@callisto.canberra.edu.au 12 | * 13 | * The current list of contributors is contained 14 | * in the file CONTRIBUTORS included with the source 15 | * code distribution. The list can also be seen at the 16 | * following World Wide Web location: 17 | * http://sources.redhat.com/pthreads-win32/contributors.html 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 2 of the License, or (at your option) any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library in the file COPYING.LIB; 31 | * if not, write to the Free Software Foundation, Inc., 32 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 33 | * 34 | * -------------------------------------------------------------------------- 35 | * 36 | * Create a simple spinlock object, lock it, and then unlock it again. 37 | * This is the simplest test of the pthread mutex family that we can do. 38 | * 39 | */ 40 | 41 | #include "test.h" 42 | 43 | pthread_spinlock_t lock; 44 | 45 | int 46 | main() 47 | { 48 | assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); 49 | 50 | assert(pthread_spin_lock(&lock) == 0); 51 | 52 | assert(pthread_spin_unlock(&lock) == 0); 53 | 54 | assert(pthread_spin_destroy(&lock) == 0); 55 | 56 | assert(pthread_spin_lock(&lock) == EINVAL); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /quickjs/src/androidMain/kotlin/com/dokar/quickjs/Platform.android.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | internal actual fun loadNativeLibrary(libraryName: String) { 4 | System.loadLibrary(libraryName) 5 | } -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/ExperimentalQuickJsApi.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | @RequiresOptIn( 4 | message = "This API is experimental. It can be changed or removed in future.", 5 | level = RequiresOptIn.Level.WARNING, 6 | ) 7 | @Retention(AnnotationRetention.BINARY) 8 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) 9 | annotation class ExperimentalQuickJsApi 10 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/QuickJsException.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | /** 4 | * It can be thrown when initializing [QuickJs] or calling its functions. 5 | */ 6 | class QuickJsException( 7 | override val message: String?, 8 | ) : Exception() 9 | 10 | @PublishedApi 11 | internal fun qjsError(message: String): Nothing = throw QuickJsException(message) 12 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/binding/Bindings.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | /** 4 | * The base binding type. 5 | */ 6 | sealed interface Binding 7 | 8 | /** 9 | * The JavaScript object binding. Properties and functions can be defined on the object. 10 | */ 11 | interface ObjectBinding : Binding { 12 | val properties: List 13 | 14 | val functions: List 15 | 16 | fun getter(name: String): Any? 17 | 18 | fun setter(name: String, value: Any?) 19 | 20 | fun invoke(name: String, args: Array): Any? 21 | } 22 | 23 | /** 24 | * The JavaScript function binding. 25 | */ 26 | fun interface FunctionBinding : Binding { 27 | fun invoke(args: Array): R 28 | } 29 | 30 | /** 31 | * The JavaScript async function binding. This provides a suspend callback. 32 | */ 33 | fun interface AsyncFunctionBinding : Binding { 34 | suspend fun invoke(args: Array): R 35 | } 36 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/binding/JsFunction.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | /** 4 | * Properties of a JavaScript function. 5 | */ 6 | class JsFunction( 7 | val name: String, 8 | val isAsync: Boolean, 9 | ) -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/binding/JsObject.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | /** 4 | * Create a delegate and mark the map as a JavaScript object. 5 | */ 6 | fun Map.toJsObject(): JsObject = JsObject(this) 7 | 8 | /** 9 | * The delegate of a property [Map] represents a JavaScript object. 10 | */ 11 | class JsObject(private val map: Map) : Map by map { 12 | override fun equals(other: Any?): Boolean { 13 | if (this === other) return true 14 | if (other !is JsObject) return false 15 | 16 | if (map != other.map) return false 17 | 18 | return true 19 | } 20 | 21 | override fun hashCode(): Int { 22 | return map.hashCode() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/binding/JsObjectHandle.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | import kotlin.jvm.JvmInline 4 | 5 | /** 6 | * The handle to a defined JavaScript object, can be used to define nested bindings. 7 | */ 8 | @JvmInline 9 | value class JsObjectHandle( 10 | val nativeHandle: Long, 11 | ) { 12 | companion object { 13 | val globalThis = JsObjectHandle(globalThisNativeHandle) 14 | } 15 | } 16 | 17 | internal expect val globalThisNativeHandle: Long -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/binding/JsProperty.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | /** 4 | * Properties of a JavaScript property. 5 | */ 6 | class JsProperty( 7 | val name: String, 8 | val configurable: Boolean, 9 | val writable: Boolean, 10 | val enumerable: Boolean, 11 | ) -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/converter/JsObjectConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.converter 2 | 3 | import com.dokar.quickjs.binding.JsObject 4 | import kotlin.reflect.KType 5 | import kotlin.reflect.typeOf 6 | 7 | /** 8 | * Converts [JsObject] to the target type [T] and vice versa. 9 | */ 10 | interface JsObjectConverter : TypeConverter { 11 | override val sourceType: KType get() = typeOf() 12 | } -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/converter/TypeConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.converter 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import kotlin.reflect.KType 5 | 6 | /** 7 | * The type converter for custom classes used by [QuickJs]'s functions. 8 | */ 9 | interface TypeConverter { 10 | /** 11 | * The source type class. 12 | */ 13 | val sourceType: KType 14 | 15 | /** 16 | * The target type class. 17 | */ 18 | val targetType: KType 19 | 20 | /** 21 | * Convert a value of type [Source] to type [Target]. 22 | */ 23 | fun convertToTarget(value: Source): Target 24 | 25 | /** 26 | * Convert a value of type [Target] back to type [Source]. 27 | */ 28 | fun convertToSource(value: Target): Source? = null 29 | } 30 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/converter/TypeConverters.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.converter 2 | 3 | import com.dokar.quickjs.qjsError 4 | import kotlin.reflect.KClass 5 | import kotlin.reflect.KType 6 | 7 | @PublishedApi 8 | internal class TypeConverters { 9 | private val converters = mutableListOf>() 10 | private val classTypeMap = mutableMapOf, KType>() 11 | 12 | fun addConverters(vararg serializers: TypeConverter<*, *>) { 13 | this.converters.addAll(serializers) 14 | for (converter in converters) { 15 | classTypeMap[converter.sourceType.classifier as KClass<*>] = converter.sourceType 16 | classTypeMap[converter.targetType.classifier as KClass<*>] = converter.targetType 17 | } 18 | } 19 | 20 | fun typeOfClass(cls: KClass<*>): KType? { 21 | return classTypeMap[cls] 22 | } 23 | 24 | @Suppress("UNCHECKED_CAST") 25 | fun convert(source: S, sourceType: KType, targetType: KType): T { 26 | if (sourceType == targetType) { 27 | return source as T 28 | } 29 | val converter = converters 30 | .find { 31 | it.sourceType.equalsWithoutNullable(sourceType) && 32 | it.targetType.equalsWithoutNullable(targetType) 33 | } 34 | as TypeConverter? 35 | if (converter != null) { 36 | return converter.convertToTarget(source) 37 | } 38 | // Try convertToSource() 39 | val backConverter = converters 40 | .find { 41 | it.sourceType.equalsWithoutNullable(targetType) && 42 | it.targetType.equalsWithoutNullable(sourceType) 43 | } 44 | as TypeConverter? 45 | if (backConverter != null) { 46 | val result = backConverter.convertToSource(source) 47 | if (result != null) { 48 | return result 49 | } 50 | } 51 | qjsError("No such type converter to convert '$sourceType' to '$targetType'") 52 | } 53 | 54 | private fun KType.equalsWithoutNullable(other: KType): Boolean { 55 | return this.classifier == other.classifier && this.arguments == other.arguments 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/converter/castValueOr.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.converter 2 | 3 | import com.dokar.quickjs.qjsError 4 | import kotlin.reflect.KType 5 | 6 | @PublishedApi 7 | internal expect fun castValueOr( 8 | value: Any?, 9 | expectedType: KType, 10 | fallback: (value: Any) -> T 11 | ): T 12 | 13 | internal fun safeCastToByteOrThrow(value: Long): Byte { 14 | if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { 15 | qjsError("Cannot cast Long($value) to Byte: value out of range.") 16 | } 17 | return value.toByte() 18 | } 19 | 20 | internal fun safeCastToShortOrThrow(value: Long): Short { 21 | if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { 22 | qjsError("Cannot cast Long($value) to Short: value out of range.") 23 | } 24 | return value.toShort() 25 | } 26 | 27 | internal fun safeCastToIntOrThrow(value: Long): Int { 28 | if (value < Int.MIN_VALUE || value > Int.MAX_VALUE) { 29 | qjsError("Cannot cast Long($value) to Int: value out of range.") 30 | } 31 | return value.toInt() 32 | } 33 | 34 | internal fun safeCastToFloatOrThrow(value: Double): Float { 35 | if (value < Float.MIN_VALUE || value > Float.MAX_VALUE) { 36 | qjsError("Cannot cast Double($value) to Float: value out of range.") 37 | } 38 | return value.toFloat() 39 | } -------------------------------------------------------------------------------- /quickjs/src/commonMain/kotlin/com/dokar/quickjs/util/Mutex.ext.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.util 2 | 3 | import kotlinx.coroutines.sync.Mutex 4 | 5 | internal inline fun Mutex.withLockSync( 6 | block: () -> T, 7 | ): T { 8 | try { 9 | while (!this.tryLock()) { 10 | // Loop until the lock is available 11 | } 12 | return block() 13 | } finally { 14 | this.unlock() 15 | } 16 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/CompileTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.quickJs 4 | import kotlinx.coroutines.test.runTest 5 | import kotlin.test.Test 6 | import kotlin.test.assertEquals 7 | import kotlin.test.assertFails 8 | 9 | class CompileTest { 10 | @Test 11 | fun compileAndEvaluate() = runTest { 12 | quickJs { 13 | val buffer = compile("1 + 2") 14 | assertEquals(3, evaluate(buffer)) 15 | } 16 | } 17 | 18 | @Test 19 | fun evaluateMalformedBytecode() = runTest { 20 | quickJs { 21 | assertFails { evaluate(byteArrayOf(0, 1, 2, 3, 4)) } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/DslAliasTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.ExperimentalQuickJsApi 4 | import com.dokar.quickjs.alias.asyncFunc 5 | import com.dokar.quickjs.alias.def 6 | import com.dokar.quickjs.alias.eval 7 | import com.dokar.quickjs.alias.func 8 | import com.dokar.quickjs.alias.prop 9 | import com.dokar.quickjs.quickJs 10 | import kotlinx.coroutines.delay 11 | import kotlinx.coroutines.test.runTest 12 | import kotlin.test.Test 13 | import kotlin.test.assertEquals 14 | 15 | class DslAliasTest { 16 | @Test 17 | fun useDslAlias() = runTest { 18 | @OptIn(ExperimentalQuickJsApi::class) 19 | quickJs { 20 | var log: Any? = null 21 | 22 | def("console") { 23 | prop("level") { 24 | getter { "Debug" } 25 | } 26 | 27 | func("log") { log = it.firstOrNull() } 28 | 29 | asyncFunc("upload") { 30 | delay(1000) 31 | "Done" 32 | } 33 | } 34 | 35 | func("fetch") { "Hello" } 36 | 37 | asyncFunc("delay") { delay(1000) } 38 | 39 | assertEquals("Debug", eval("console.level")) 40 | 41 | eval("console.log('Hi')") 42 | assertEquals("Hi", log) 43 | 44 | assertEquals("Done", eval("await console.upload()")) 45 | 46 | assertEquals("Hello", eval("fetch()")) 47 | 48 | val bytecode = compile(code = "fetch()") 49 | assertEquals("Hello", eval(bytecode)) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/FlowToAsyncIteratorTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.binding.asyncFunction 4 | import com.dokar.quickjs.quickJs 5 | import kotlinx.coroutines.DelicateCoroutinesApi 6 | import kotlinx.coroutines.channels.Channel 7 | import kotlinx.coroutines.delay 8 | import kotlinx.coroutines.flow.flow 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.test.runTest 11 | import kotlin.test.Test 12 | import kotlin.test.assertContentEquals 13 | 14 | class FlowToAsyncIteratorTest { 15 | @OptIn(DelicateCoroutinesApi::class) 16 | @Test 17 | fun flowToAsyncIterator() = runTest { 18 | val flow = flow { 19 | repeat(5) { 20 | delay(500) 21 | emit(it) 22 | } 23 | } 24 | 25 | var started = false 26 | val channel = Channel() 27 | fun startCollecting() { 28 | started = true 29 | launch { 30 | flow.collect(channel::send) 31 | channel.close() 32 | } 33 | } 34 | 35 | quickJs { 36 | asyncFunction("nextFlowValue") { 37 | if (!started) { 38 | startCollecting() 39 | } 40 | if (!channel.isClosedForReceive) { 41 | channel.receive() 42 | } else { 43 | null 44 | } 45 | } 46 | 47 | val result = evaluate>( 48 | """ 49 | async function* numbers() { 50 | while (true) { 51 | const value = await nextFlowValue(); 52 | if (value == null) { 53 | break; 54 | } 55 | yield value; 56 | } 57 | } 58 | 59 | const array = []; 60 | for await (const value of numbers()) { 61 | array.push(value); 62 | } 63 | 64 | array; 65 | """.trimIndent() 66 | ) 67 | assertContentEquals(List(5) { it.toLong() }, result) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/JsPromiseTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.binding.function 4 | import com.dokar.quickjs.quickJs 5 | import kotlinx.coroutines.test.runTest 6 | import kotlin.test.Test 7 | import kotlin.test.assertEquals 8 | 9 | class JsPromiseTest { 10 | @Test 11 | fun asyncFunction() = runTest { 12 | quickJs { 13 | val result = evaluate( 14 | """ 15 | async function add(a, b) { 16 | return a + b; 17 | } 18 | await add(1, 2) 19 | """.trimIndent() 20 | ) 21 | assertEquals(3, result) 22 | } 23 | } 24 | 25 | @Test 26 | fun promise() = runTest { 27 | quickJs { 28 | val result = evaluate( 29 | """ 30 | await new Promise((resolve) => resolve(1)) 31 | .then((result) => result + 1) 32 | """.trimIndent() 33 | ) 34 | assertEquals(2, result) 35 | } 36 | } 37 | 38 | @Test 39 | fun promiseDotAll() = runTest { 40 | quickJs { 41 | val result = evaluate>( 42 | """ 43 | async function add(a, b) { 44 | return a + b; 45 | } 46 | await Promise.all([add(1, 2), add(3, 4)]) 47 | """.trimIndent() 48 | ) 49 | assertEquals(listOf(3L, 7L), result) 50 | } 51 | } 52 | 53 | @Test 54 | fun promiseWithoutAwait() = runTest { 55 | quickJs { 56 | val logs = mutableListOf() 57 | 58 | function("log") { logs += it } 59 | 60 | evaluate( 61 | """ 62 | log("Start"); 63 | new Promise((resolve) => resolve()) 64 | .then(() => log("Then")); 65 | log("End"); 66 | """.trimIndent() 67 | ) 68 | 69 | assertEquals(listOf("Start", "End", "Then"), logs) 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/MultiRuntimeTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.define 5 | import kotlinx.coroutines.CoroutineDispatcher 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.IO 8 | import kotlinx.coroutines.test.runTest 9 | import kotlin.test.Test 10 | import kotlin.test.assertEquals 11 | import kotlin.test.assertTrue 12 | 13 | class MultiRuntimeTest { 14 | @OptIn(ExperimentalStdlibApi::class) 15 | @Test 16 | fun runMultipleRuntimes() = runTest { 17 | runAndVerify(coroutineContext[CoroutineDispatcher]!!) 18 | } 19 | 20 | @Test 21 | fun runMultipleRuntimesInMultiThreads() = runTest { 22 | runAndVerify(Dispatchers.IO) 23 | } 24 | 25 | private suspend fun runAndVerify(dispatcher: CoroutineDispatcher) { 26 | val apps = List(10) { 27 | App( 28 | name = "App $it", 29 | version = "1.0.$it" 30 | ) 31 | } 32 | 33 | val runtimes = apps.map { initRuntime(it, dispatcher) } 34 | 35 | for (i in apps.indices) { 36 | val app = apps[i] 37 | val runtime = runtimes[i] 38 | assertEquals(app.name, runtime.evaluate("app.name")) 39 | assertEquals(app.version, runtime.evaluate("app.version")) 40 | runtime.evaluate("app.launch()") 41 | assertTrue(app.launched) 42 | } 43 | 44 | runtimes.forEach { it.close() } 45 | } 46 | 47 | private fun initRuntime( 48 | app: App, 49 | dispatcher: CoroutineDispatcher, 50 | ) = QuickJs.create(jobDispatcher = dispatcher).apply { 51 | define("app") { 52 | property("name") { 53 | getter { app.name } 54 | } 55 | 56 | property("version") { 57 | getter { app.version } 58 | } 59 | 60 | function("launch") { app.launched = true } 61 | } 62 | } 63 | 64 | private class App( 65 | val name: String, 66 | val version: String, 67 | var launched: Boolean = false, 68 | ) 69 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/MultiThreadShareRuntime.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.function 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.ExperimentalCoroutinesApi 7 | import kotlinx.coroutines.IO 8 | import kotlinx.coroutines.joinAll 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.test.UnconfinedTestDispatcher 11 | import kotlinx.coroutines.test.runTest 12 | import kotlin.test.Test 13 | import kotlin.test.assertEquals 14 | 15 | class MultiThreadShareRuntime { 16 | @OptIn(ExperimentalCoroutinesApi::class) 17 | @Test 18 | fun shareRuntime() = runTest { 19 | val quickJs = QuickJs.create(UnconfinedTestDispatcher()) 20 | try { 21 | with(quickJs) { 22 | function("add") { it.first() as Long + it[1] as Long } 23 | } 24 | val jobs = List(20) { 25 | launch(Dispatchers.IO) { 26 | assertEquals(3L, quickJs.evaluate("add(1, 2)")) 27 | } 28 | } 29 | jobs.joinAll() 30 | } finally { 31 | quickJs.close() 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/MultiThreadStackOverflowTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.binding.asyncFunction 4 | import com.dokar.quickjs.quickJs 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.ExperimentalCoroutinesApi 7 | import kotlinx.coroutines.IO 8 | import kotlinx.coroutines.delay 9 | import kotlinx.coroutines.test.runTest 10 | import kotlin.test.Test 11 | 12 | class MultiThreadStackOverflowTest { 13 | @OptIn(ExperimentalCoroutinesApi::class) 14 | @Test 15 | fun stackOverflowWhenExecutingJobs() = runTest { 16 | // This ensures that our async jobs are executed in different threads 17 | quickJs(jobDispatcher = Dispatchers.IO.limitedParallelism(100)) { 18 | maxStackSize = 512 * 1024 * 1024 19 | 20 | asyncFunction("runJob") { delay(50) } 21 | 22 | // This CAN throw a stack overflow error if executePendingJob() 23 | // is not thread-safe. 24 | evaluate( 25 | """ 26 | const jobs = []; 27 | for (let i = 0; i < 1000; i++) { 28 | jobs.push(runJob()); 29 | } 30 | await Promise.all(jobs); 31 | """.trimIndent() 32 | ) 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/QuickJsPropertiesTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.quickJs 4 | import kotlinx.coroutines.test.runTest 5 | import kotlin.test.Test 6 | import kotlin.test.assertContains 7 | import kotlin.test.assertEquals 8 | 9 | class QuickJsPropertiesTest { 10 | @Test 11 | fun version() = runTest { 12 | quickJs { 13 | assertContains(version, "20") 14 | } 15 | } 16 | 17 | @Test 18 | fun memoryLimit() =runTest { 19 | quickJs { 20 | assertEquals(-1, memoryLimit) 21 | val newLimit = 10 * 1024 * 1024L 22 | memoryLimit = newLimit 23 | assertEquals(newLimit, memoryUsage.mallocLimit) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /quickjs/src/commonTest/kotlin/com/dokar/quickjs/test/TypeMappingTest.ByteArray.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.binding.function 4 | import com.dokar.quickjs.quickJs 5 | import kotlinx.coroutines.test.runTest 6 | import kotlin.test.Test 7 | import kotlin.test.assertContentEquals 8 | 9 | class UInt8ArrayMapping { 10 | @Test 11 | fun byteArrays() = runTest { 12 | val array = byteArrayOf(0, 1, 10, 127) 13 | quickJs { 14 | function("getBuffer") { array } 15 | 16 | assertContentEquals(array, evaluate("getBuffer()")) 17 | } 18 | } 19 | 20 | @OptIn(ExperimentalUnsignedTypes::class) 21 | @Test 22 | fun uByteArrays() = runTest { 23 | val array = ubyteArrayOf(0u, 10u, 100u, 255u) 24 | quickJs { 25 | function("getBuffer") { array } 26 | 27 | assertContentEquals(array, evaluate("getBuffer()")) 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /quickjs/src/jniMain/kotlin/com/dokar/quickjs/Platform.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | internal expect fun loadNativeLibrary(libraryName: String) -------------------------------------------------------------------------------- /quickjs/src/jniMain/kotlin/com/dokar/quickjs/alias/dslAlias.jni.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.alias 2 | 3 | import com.dokar.quickjs.ExperimentalQuickJsApi 4 | import com.dokar.quickjs.QuickJs 5 | import com.dokar.quickjs.QuickJsException 6 | import com.dokar.quickjs.binding.JsObjectHandle 7 | import com.dokar.quickjs.binding.define 8 | import com.dokar.quickjs.evaluate 9 | import kotlin.reflect.KType 10 | 11 | /** 12 | * Alias for inline version of [QuickJs.define]. 13 | */ 14 | @ExperimentalQuickJsApi 15 | inline fun QuickJs.def( 16 | name: String, 17 | instance: Any, 18 | parent: JsObjectHandle = JsObjectHandle.globalThis, 19 | ) { 20 | define(name = name, instance = instance, parent = parent) 21 | } 22 | 23 | /** 24 | * Alias for [QuickJs.define]. 25 | */ 26 | @ExperimentalQuickJsApi 27 | fun QuickJs.def( 28 | name: String, 29 | type: Class, 30 | instance: Any, 31 | parent: JsObjectHandle = JsObjectHandle.globalThis, 32 | ) { 33 | define(name = name, type = type, instance = instance, parent = parent) 34 | } 35 | 36 | /** 37 | * Alias for [QuickJs.evaluate]. 38 | */ 39 | @ExperimentalQuickJsApi 40 | @Throws(QuickJsException::class) 41 | suspend fun QuickJs.eval( 42 | bytecode: ByteArray, 43 | type: KType 44 | ): T { 45 | return evaluate(bytecode = bytecode, type = type) 46 | } 47 | 48 | /** 49 | * Alias for [QuickJs.evaluate]. 50 | */ 51 | @ExperimentalQuickJsApi 52 | @Throws(QuickJsException::class) 53 | suspend fun QuickJs.eval( 54 | code: String, 55 | type: KType, 56 | filename: String = "main.js", 57 | asModule: Boolean = false 58 | ): T { 59 | return evaluate(code = code, type = type, filename = filename, asModule = asModule) 60 | } -------------------------------------------------------------------------------- /quickjs/src/jniMain/kotlin/com/dokar/quickjs/binding/JsObjectHandle.jni.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | // Handles are index based, reserve -1 for the globalThis 4 | internal actual val globalThisNativeHandle: Long = -1 -------------------------------------------------------------------------------- /quickjs/src/jniTest/kotlin/com/dokar/quickjs/test/JvmValueCastingTest.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.test 2 | 3 | import com.dokar.quickjs.converter.castValueOr 4 | import kotlin.reflect.KType 5 | import kotlin.reflect.typeOf 6 | import kotlin.test.Test 7 | import kotlin.test.assertEquals 8 | 9 | class JvmValueCastingTest { 10 | @Test 11 | fun unboxBooleans() { 12 | assertEquals( 13 | false, castValueOrThrow(java.lang.Boolean.valueOf(false), typeOf()) 14 | ) 15 | } 16 | 17 | @Test 18 | fun unboxInts() { 19 | assertEquals( 20 | 1, castValueOrThrow(Integer.valueOf(1), typeOf()) 21 | ) 22 | } 23 | 24 | @Test 25 | fun unboxLongs() { 26 | assertEquals( 27 | 1L, castValueOrThrow(java.lang.Long.valueOf(1L), typeOf()) 28 | ) 29 | } 30 | 31 | @Test 32 | fun unboxFloats() { 33 | assertEquals( 34 | 1f, castValueOrThrow(java.lang.Float.valueOf(1f), typeOf()) 35 | ) 36 | } 37 | 38 | @Test 39 | fun unboxDoubles() { 40 | assertEquals( 41 | 1.0, castValueOrThrow(java.lang.Double.valueOf(1.0), typeOf()) 42 | ) 43 | } 44 | 45 | @Test 46 | fun longToInt() { 47 | assertEquals(1, castValueOrThrow(1L, typeOf())) 48 | assertEquals(1, castValueOrThrow(java.lang.Long.valueOf(1L), typeOf())) 49 | assertEquals( 50 | 1, castValueOrThrow(java.lang.Long.valueOf(1L), typeOf()) 51 | ) 52 | } 53 | 54 | @Test 55 | fun doubleToFloat() { 56 | assertEquals(1f, castValueOrThrow(java.lang.Double.valueOf(1.0), typeOf())) 57 | assertEquals( 58 | 1f, castValueOrThrow(java.lang.Double.valueOf(1.0), typeOf()) 59 | ) 60 | } 61 | } 62 | 63 | private inline fun castValueOrThrow( 64 | value: Any?, 65 | expectedType: KType, 66 | ): T { 67 | Result.success(2).getOrElse { error("") } 68 | return castValueOr( 69 | value, 70 | expectedType 71 | ) { 72 | error("Failed to convert ${it::class} to $expectedType") 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /quickjs/src/jvmMain/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | CMakeFiles/ 4 | CMakeCache.txt 5 | -------------------------------------------------------------------------------- /quickjs/src/jvmMain/kotlin/com/dokar/quickjs/Platform.jvm.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs 2 | 3 | import java.io.IOException 4 | import java.nio.file.Files 5 | import java.nio.file.Path 6 | import java.nio.file.StandardCopyOption.REPLACE_EXISTING 7 | import java.util.Locale.US 8 | 9 | // Based on https://github.com/cashapp/zipline/blob/trunk/zipline/src/jvmMain/kotlin/app/cash/zipline/QuickJsNativeLoader.kt 10 | // Updated to support Windows dll 11 | @Suppress("UnsafeDynamicallyLoadedCode") 12 | internal actual fun loadNativeLibrary(libraryName: String) { 13 | val osName = System.getProperty("os.name").lowercase(US) 14 | val arch = when (val osArch = System.getProperty("os.arch").lowercase(US)) { 15 | "amd64" -> "x64" 16 | "x86_64" -> "x64" 17 | "aarch64" -> osArch 18 | else -> throw IllegalStateException("Unsupported arch: '${osArch}'") 19 | } 20 | val nativeLibraryJarPath = if (osName.contains("linux")) { 21 | "/jni/linux_$arch/libquickjs.so" 22 | } else if (osName.contains("mac")) { 23 | "/jni/macos_$arch/libquickjs.dylib" 24 | } else if (osName.contains("windows") && arch == "x64") { 25 | "/jni/windows_$arch/libquickjs.dll" 26 | } else { 27 | throw IllegalStateException("Unsupported OS and arch: $osName, $arch") 28 | } 29 | val classLoader = QuickJs::class.java.classLoader!! 30 | val nativeLibraryUrl = classLoader.getResource(nativeLibraryJarPath) 31 | ?: classLoader.getResource(nativeLibraryJarPath.substring(1)) // Relative path 32 | ?: throw IllegalStateException("Unable to read $nativeLibraryJarPath from JAR") 33 | val nativeLibraryFile: Path 34 | try { 35 | nativeLibraryFile = Files.createTempFile("quickjs", null) 36 | 37 | // File-based deleteOnExit() uses a special internal shutdown hook that always runs last. 38 | nativeLibraryFile.toFile().deleteOnExit() 39 | nativeLibraryUrl.openStream().use { nativeLibrary -> 40 | Files.copy(nativeLibrary, nativeLibraryFile, REPLACE_EXISTING) 41 | } 42 | } catch (e: IOException) { 43 | throw RuntimeException("Unable to extract native library from JAR", e) 44 | } 45 | System.load(nativeLibraryFile.toAbsolutePath().toString()) 46 | } -------------------------------------------------------------------------------- /quickjs/src/nativeInterop/cinterop/quickjs.def: -------------------------------------------------------------------------------- 1 | # Based on: https://github.com/cashapp/zipline/blob/5244f7c4c4f5c4263e40f2682e6bf7c6484e8020/zipline/src/nativeInterop/cinterop/quickjs.def 2 | 3 | staticLibraries.mingw_x64 = libquickjs_windows_x64.a 4 | staticLibraries.linux_x64 = libquickjs_linux_x64.a 5 | staticLibraries.linux_arm64 = libquickjs_linux_aarch64.a 6 | staticLibraries.macos_x64 = libquickjs_macos_x64.a 7 | staticLibraries.macos_arm64 = libquickjs_macos_aarch64.a 8 | staticLibraries.ios_x64 = libquickjs_ios_x64.a 9 | staticLibraries.ios_arm64 = libquickjs_ios_aarch64.a 10 | staticLibraries.ios_simulator_arm64 = libquickjs_ios_simulator_aarch64.a 11 | 12 | libraryPaths = native/build/static_libs/ 13 | 14 | noStringConversion = \ 15 | JS_Eval \ 16 | JS_NewString \ 17 | JS_FreeCString 18 | 19 | --- 20 | 21 | // Avoid types ending up in cnames.structs.* https://youtrack.jetbrains.com/issue/KT-49034 22 | 23 | typedef struct JSContext {} JSContext; 24 | typedef struct JSRuntime {} JSRuntime; 25 | 26 | // Exposing non-constant macros per https://kotlinlang.org/docs/native-c-interop.html#macros 27 | 28 | static inline int JsValueGetNormTag(JSValue v) { 29 | return JS_VALUE_GET_NORM_TAG(v); 30 | } 31 | 32 | static inline int JsValueGetInt(JSValue v) { 33 | return JS_VALUE_GET_INT(v); 34 | } 35 | 36 | static inline int JsValueGetBool(JSValue v) { 37 | return JS_VALUE_GET_BOOL(v); 38 | } 39 | 40 | static inline double JsValueGetFloat64(JSValue v) { 41 | return JS_VALUE_GET_FLOAT64(v); 42 | } 43 | 44 | static inline int JsValueGetPtr(JSValue v) { 45 | return JS_VALUE_GET_PTR(v); 46 | } 47 | 48 | static inline JSValue JsNull() { 49 | return JS_NULL; 50 | } 51 | 52 | static inline JSValue JsUndefined() { 53 | return JS_UNDEFINED; 54 | } 55 | 56 | static inline JSValue JsTrue() { 57 | return JS_TRUE; 58 | } 59 | 60 | static inline JSValue JsFalse() { 61 | return JS_FALSE; 62 | } 63 | 64 | static inline JSValue JsException() { 65 | return JS_EXCEPTION; 66 | } 67 | -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/binding/JsObjectHandle.native.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.binding 2 | 3 | // Handles are address based, reserve 0 for the globalThis 4 | internal actual val globalThisNativeHandle: Long = 0 -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/bridge/BindingFunctionData.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.bridge 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import kotlinx.cinterop.CPointer 5 | import kotlinx.cinterop.ExperimentalForeignApi 6 | import kotlinx.cinterop.alloc 7 | import kotlinx.cinterop.asStableRef 8 | import kotlinx.cinterop.get 9 | import kotlinx.cinterop.memScoped 10 | import kotlinx.cinterop.ptr 11 | import kotlinx.cinterop.readValue 12 | import kotlinx.cinterop.toCPointer 13 | import kotlinx.cinterop.value 14 | import platform.posix.int64_tVar 15 | import quickjs.JSContext 16 | import quickjs.JSValue 17 | import quickjs.JS_ToInt64 18 | 19 | internal data class BindingFunctionData( 20 | val name: String, 21 | val quickJs: QuickJs, 22 | val objectHandle: Long, 23 | ) { 24 | companion object { 25 | @OptIn(ExperimentalForeignApi::class) 26 | fun fromJsValues( 27 | ctx: CPointer?, 28 | data: CPointer, 29 | ): BindingFunctionData = memScoped { 30 | // Read property name 31 | val name = data[0].readValue().toKtString(ctx!!)!! 32 | 33 | // Read the QuickJs instance 34 | val qjsAddress = alloc() 35 | JS_ToInt64(ctx, qjsAddress.ptr, data[1].readValue()) 36 | val qjsVoidPtr = qjsAddress.value.toCPointer() 37 | val qjsStableRef = qjsVoidPtr!!.asStableRef() 38 | val quickJs = qjsStableRef.get() 39 | 40 | // Read object handle 41 | val objectHandle = alloc() 42 | JS_ToInt64(ctx, objectHandle.ptr, data[2].readValue()) 43 | 44 | BindingFunctionData( 45 | name = name, 46 | quickJs = quickJs, 47 | objectHandle = objectHandle.value, 48 | ) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/bridge/errors.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.bridge 2 | 3 | import com.dokar.quickjs.qjsError 4 | 5 | internal fun circularRefError(): Nothing = 6 | qjsError("Unable to map objects with circular reference.") -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/bridge/invokeJsFunction.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.bridge 2 | 3 | import com.dokar.quickjs.util.allocArrayOf 4 | import kotlinx.cinterop.CPointer 5 | import kotlinx.cinterop.CValue 6 | import kotlinx.cinterop.ExperimentalForeignApi 7 | import kotlinx.cinterop.memScoped 8 | import quickjs.JSContext 9 | import quickjs.JSValue 10 | import quickjs.JS_Call 11 | import quickjs.JS_FreeValue 12 | import quickjs.JS_GetRuntime 13 | import quickjs.JS_UpdateStackTop 14 | import quickjs.JsNull 15 | 16 | @OptIn(ExperimentalForeignApi::class) 17 | internal fun CPointer.invokeJsFunction( 18 | func: CValue, 19 | args: Array, 20 | ): Unit = memScoped { 21 | val context = this@invokeJsFunction 22 | 23 | JS_UpdateStackTop(JS_GetRuntime(context)) 24 | 25 | val jsArgs = Array(args.size) { JsNull() } 26 | for (i in jsArgs.indices) { 27 | try { 28 | jsArgs[i] = args[i].toJsValue(context) 29 | } catch (e: Throwable) { 30 | for (j in 0...ktMemoryUsage(): MemoryUsage = memScoped { 15 | val usage = alloc() 16 | JS_ComputeMemoryUsage(this@ktMemoryUsage, usage.ptr) 17 | MemoryUsage( 18 | mallocLimit = usage.malloc_limit, 19 | mallocCount = usage.malloc_count, 20 | mallocSize = usage.malloc_size, 21 | memoryUsedCount = usage.memory_used_count, 22 | memoryUsedSize = usage.memory_used_size, 23 | atomCount = usage.atom_count, 24 | atomSize = usage.atom_size, 25 | strCount = usage.str_count, 26 | strSize = usage.str_size, 27 | objCount = usage.obj_count, 28 | objSize = usage.obj_size, 29 | propCount = usage.prop_count, 30 | propSize = usage.prop_size, 31 | shapeCount = usage.shape_count, 32 | shapeSize = usage.shape_size, 33 | jsFuncCount = usage.js_func_count, 34 | jsFuncSize = usage.js_func_size, 35 | jsFuncCodeSize = usage.js_func_code_size, 36 | jsFuncPc2lineCount = usage.js_func_pc2line_count, 37 | jsFuncPc2lineSize = usage.js_func_pc2line_size, 38 | cFuncCount = usage.c_func_count, 39 | arrayCount = usage.array_count, 40 | fastArrayCount = usage.fast_array_count, 41 | fastArrayElements = usage.fast_array_elements, 42 | binaryObjectCount = usage.binary_object_count, 43 | binaryObjectSize = usage.binary_object_size, 44 | ) 45 | } -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/bridge/promiseRejectionHandler.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.bridge 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import kotlinx.cinterop.COpaquePointer 5 | import kotlinx.cinterop.CPointer 6 | import kotlinx.cinterop.CValue 7 | import kotlinx.cinterop.ExperimentalForeignApi 8 | import kotlinx.cinterop.StableRef 9 | import kotlinx.cinterop.asStableRef 10 | import kotlinx.cinterop.staticCFunction 11 | import quickjs.JSContext 12 | import quickjs.JSRuntime 13 | import quickjs.JSValue 14 | import quickjs.JS_SetHostPromiseRejectionTracker 15 | 16 | @Suppress("UNUSED_PARAMETER") 17 | @OptIn(ExperimentalForeignApi::class) 18 | private fun promiseRejectionHandler( 19 | context: CPointer?, 20 | promise: CValue, 21 | reason: CValue, 22 | isHandled: Int, 23 | opaque: COpaquePointer?, 24 | ) { 25 | if (isHandled != 1) { 26 | val quickJs = opaque!!.asStableRef() 27 | quickJs.get().setUnhandledPromiseRejection(reason.toKtValue(context!!)) 28 | } 29 | } 30 | 31 | @OptIn(ExperimentalForeignApi::class) 32 | internal fun setPromiseRejectionHandler( 33 | quickJs: StableRef, 34 | runtime: CPointer, 35 | ) { 36 | JS_SetHostPromiseRejectionTracker( 37 | rt = runtime, 38 | cb = staticCFunction(::promiseRejectionHandler), 39 | opaque = quickJs.asCPointer(), 40 | ) 41 | } -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/bridge/useJsValue.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.bridge 2 | 3 | import kotlinx.cinterop.CPointer 4 | import kotlinx.cinterop.CValue 5 | import kotlinx.cinterop.ExperimentalForeignApi 6 | import quickjs.JSContext 7 | import quickjs.JSValue 8 | import quickjs.JS_FreeValue 9 | 10 | @OptIn(ExperimentalForeignApi::class) 11 | internal inline fun CValue.use( 12 | context: CPointer, 13 | block: CValue.() -> T 14 | ): T { 15 | try { 16 | return block() 17 | } finally { 18 | JS_FreeValue(context, this) 19 | } 20 | } -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/converter/castValueOr.native.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.converter 2 | 3 | import kotlin.reflect.KClass 4 | import kotlin.reflect.KType 5 | 6 | @Suppress("unchecked_cast") 7 | @PublishedApi 8 | internal actual fun castValueOr( 9 | value: Any?, 10 | expectedType: KType, 11 | fallback: (value: Any) -> T 12 | ): T { 13 | val nonNull = value ?: return null as T 14 | val expectedClass = expectedType.classifier as KClass<*> 15 | if (expectedClass.isInstance(value)) { 16 | return nonNull as T 17 | } 18 | when (expectedClass) { 19 | Byte::class -> { 20 | if (value is Long) { 21 | return safeCastToByteOrThrow(value) as T 22 | } 23 | } 24 | 25 | Short::class -> { 26 | if (value is Long) { 27 | return safeCastToShortOrThrow(value) as T 28 | } 29 | } 30 | 31 | Int::class -> { 32 | when (value) { 33 | is Long -> { 34 | // Long -> int 35 | return safeCastToIntOrThrow(value) as T 36 | } 37 | } 38 | } 39 | 40 | Float::class -> { 41 | when (value) { 42 | is Double -> { 43 | // Double -> float 44 | return safeCastToFloatOrThrow(value) as T 45 | } 46 | 47 | is Long -> { 48 | // Long -> float 49 | return value.toFloat() as T 50 | } 51 | } 52 | } 53 | 54 | Double::class -> { 55 | if (value is Long) { 56 | // Long -> double 57 | return value.toDouble() as T 58 | } 59 | } 60 | } 61 | return fallback(value) 62 | } 63 | -------------------------------------------------------------------------------- /quickjs/src/nativeMain/kotlin/com/dokar/quickjs/util/allocArray.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.util 2 | 3 | import kotlinx.cinterop.CArrayPointer 4 | import kotlinx.cinterop.CValues 5 | import kotlinx.cinterop.CVariable 6 | import kotlinx.cinterop.ExperimentalForeignApi 7 | import kotlinx.cinterop.MemScope 8 | import kotlinx.cinterop.allocArray 9 | import kotlinx.cinterop.ptr 10 | 11 | @ExperimentalForeignApi 12 | internal inline fun MemScope.allocArrayOf( 13 | vararg elements: CValues 14 | ): CArrayPointer { 15 | val array = allocArray(elements.size) { 16 | elements[it].place(this.ptr) 17 | } 18 | return array 19 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /samples/js-eval/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .gradle/ 3 | 4 | *.log 5 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/.gitignore -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/kotlin/quickjs/sample/eval/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.eval 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.material3.MaterialTheme 7 | import androidx.compose.material3.Surface 8 | import androidx.compose.material3.darkColorScheme 9 | 10 | class MainActivity : ComponentActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContent { 14 | MaterialTheme(colorScheme = darkColorScheme()) { 15 | Surface { 16 | EvalScreen() 17 | } 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/js-eval/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | js eval 3 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /samples/js-eval/src/androidMain/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /samples/js-eval/src/desktopMain/kotlin/quickjs/sample/eval/Main.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.eval 2 | 3 | import androidx.compose.material3.MaterialTheme 4 | import androidx.compose.material3.Surface 5 | import androidx.compose.material3.darkColorScheme 6 | import androidx.compose.ui.window.Window 7 | import androidx.compose.ui.window.application 8 | 9 | fun main() = application { 10 | Window(onCloseRequest = ::exitApplication, title = "js-eval") { 11 | MaterialTheme(colorScheme = darkColorScheme()) { 12 | Surface { 13 | EvalScreen() 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/openai/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .gradle/ 3 | 4 | *.log 5 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/.gitignore -------------------------------------------------------------------------------- /samples/openai/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/kotlin/quickjs/sample/openai/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.openai 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.material3.MaterialTheme 7 | import androidx.compose.material3.Surface 8 | import androidx.compose.material3.darkColorScheme 9 | 10 | class MainActivity : ComponentActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContent { 14 | MaterialTheme(colorScheme = darkColorScheme()) { 15 | Surface { 16 | OpenAISampleScreen() 17 | } 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /samples/openai/src/androidMain/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/samples/openai/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OpenAI SDK 3 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /samples/openai/src/androidMain/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /samples/openai/src/commonMain/kotlin/quickjs/sample/openai/bindings/cleanup.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.openai.bindings 2 | 3 | internal typealias Cleanup = () -> Unit 4 | -------------------------------------------------------------------------------- /samples/openai/src/commonMain/kotlin/quickjs/sample/openai/bindings/env.kt: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.QuickJs 2 | import com.dokar.quickjs.binding.define 3 | 4 | /** 5 | * Define env variables on `process.env`. 6 | */ 7 | internal fun QuickJs.defineEnv(map: Map) { 8 | define("process") { 9 | define("env") { 10 | for (env in map) { 11 | property(env.key) { 12 | getter { env.value } 13 | } 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /samples/openai/src/commonMain/kotlin/quickjs/sample/openai/bindings/setTimeout.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.openai.bindings 2 | 3 | import com.dokar.quickjs.QuickJs 4 | import com.dokar.quickjs.binding.asyncFunction 5 | import com.dokar.quickjs.binding.function 6 | import kotlinx.coroutines.Job 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | import kotlinx.coroutines.delay 10 | 11 | internal suspend fun QuickJs.defineSetTimeout(): Cleanup { 12 | var delayId = 1L 13 | val delays = mutableMapOf() 14 | 15 | val cleanup: Cleanup = { 16 | for (job in delays.values) { 17 | job.cancel() 18 | } 19 | } 20 | 21 | function("_nextDelayId") { delayId++ } 22 | 23 | function("_cancelDelayInternal") { args -> 24 | delays.remove(args.first() as Long)?.cancel() 25 | } 26 | 27 | asyncFunction("_delayInternal") { args -> 28 | val millis = args.first() as Long 29 | val id = args[1] as Long 30 | coroutineScope { 31 | val job = async { delay(millis) } 32 | delays[id] = job 33 | // Will throw if job is canceled 34 | job.await() 35 | } 36 | } 37 | 38 | evaluate( 39 | """ 40 | function setTimeout(callback, timeout) { 41 | const id = _nextDelayId(); 42 | _delayInternal(timeout, id) 43 | .then(() => callback()) 44 | .catch((e) => {}); 45 | return id; 46 | } 47 | 48 | function clearTimeout(id) { 49 | _cancelDelayInternal(id) 50 | } 51 | """.trimIndent(), 52 | filename = "setTimeout.js" 53 | ) 54 | 55 | return cleanup 56 | } 57 | -------------------------------------------------------------------------------- /samples/openai/src/desktopMain/kotlin/quickjs/sample/openai/Main.kt: -------------------------------------------------------------------------------- 1 | package quickjs.sample.openai 2 | 3 | import androidx.compose.material3.MaterialTheme 4 | import androidx.compose.material3.Surface 5 | import androidx.compose.material3.darkColorScheme 6 | import androidx.compose.ui.window.Window 7 | import androidx.compose.ui.window.application 8 | 9 | fun main() = application { 10 | Window(onCloseRequest = ::exitApplication, title = "openai-sdk") { 11 | MaterialTheme(colorScheme = darkColorScheme()) { 12 | Surface { 13 | OpenAISampleScreen() 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/repl/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /samples/repl/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.disableUnsupportedPlatformTasks 2 | 3 | plugins { 4 | id("application") 5 | alias(libs.plugins.kotlinMultiplatform) 6 | id("com.github.johnrengelman.shadow") version "8.1.1" 7 | } 8 | 9 | kotlin { 10 | jvm { 11 | withJava() 12 | } 13 | 14 | mingwX64 { 15 | binaries { 16 | executable() 17 | } 18 | } 19 | linuxX64 { 20 | binaries { 21 | executable() 22 | } 23 | } 24 | 25 | applyDefaultHierarchyTemplate() 26 | 27 | jvmToolchain { 28 | languageVersion.set(JavaLanguageVersion.of(17)) 29 | } 30 | 31 | sourceSets { 32 | val commonMain by getting { 33 | dependencies { 34 | implementation(projects.quickjs) 35 | implementation(libs.kotlinx.coroutines.core) 36 | implementation(libs.clikt) 37 | } 38 | } 39 | } 40 | } 41 | 42 | java { 43 | sourceCompatibility = JavaVersion.VERSION_17 44 | targetCompatibility = JavaVersion.VERSION_17 45 | } 46 | 47 | application { 48 | mainClass.set("ReplMainKt") 49 | } 50 | 51 | disableUnsupportedPlatformTasks() 52 | -------------------------------------------------------------------------------- /samples/repl/src/commonMain/kotlin/com/dokar/quickjs/sample/repl/ReplCliApp.kt: -------------------------------------------------------------------------------- 1 | package com.dokar.quickjs.sample.repl 2 | 3 | import com.dokar.quickjs.binding.define 4 | import com.dokar.quickjs.quickJs 5 | import com.github.ajalt.clikt.core.CliktCommand 6 | import com.github.ajalt.clikt.core.terminal 7 | import kotlinx.coroutines.isActive 8 | import kotlinx.coroutines.runBlocking 9 | 10 | class ReplCliApp : CliktCommand() { 11 | private val exitCommands = setOf("exit()", ".exit") 12 | 13 | override fun run() = runBlocking { 14 | quickJs { 15 | define("console") { 16 | function("log") { terminal.println(it.joinToString(" ")) } 17 | function("info") { terminal.println(it.joinToString(" ")) } 18 | function("warn") { terminal.println(it.joinToString(" ")) } 19 | function("error") { terminal.danger(it.joinToString(" "), stderr = true) } 20 | } 21 | 22 | while (isActive) { 23 | val input = terminal.prompt("qjs>") ?: break 24 | if (input.isBlank()) { 25 | continue 26 | } 27 | if (input in exitCommands) { 28 | break 29 | } 30 | val result = runCatching { evaluate(input) } 31 | if (result.isSuccess) { 32 | terminal.println(result.getOrNull()?.toString() ?: "") 33 | } else { 34 | terminal.danger(result.exceptionOrNull()!!.message, stderr = true) 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /samples/repl/src/jvmMain/kotlin/ReplMain.kt: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.sample.repl.ReplCliApp 2 | 3 | fun main(args: Array) = ReplCliApp().main(args) 4 | -------------------------------------------------------------------------------- /samples/repl/src/nativeMain/kotlin/ReplMain.kt: -------------------------------------------------------------------------------- 1 | import com.dokar.quickjs.sample.repl.ReplCliApp 2 | 3 | fun main(args: Array) = ReplCliApp().main(args) -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /scripts/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokar3/quickjs-kt/9457f7768e51cc1eefadba0fdd4d2f34a87e55be/scripts/bun.lockb -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": {}, 3 | "devDependencies": { 4 | "@types/bun": "^1.0.5" 5 | } 6 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google { 4 | content { 5 | includeGroupByRegex("com\\.android.*") 6 | includeGroupByRegex("com\\.google.*") 7 | includeGroupByRegex("androidx.*") 8 | } 9 | } 10 | mavenCentral() 11 | gradlePluginPortal() 12 | } 13 | } 14 | dependencyResolutionManagement { 15 | repositoriesMode.set(RepositoriesMode.PREFER_PROJECT) 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | rootProject.name = "quickjs-kt" 23 | 24 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 25 | 26 | include(":quickjs") 27 | include(":quickjs-converter-ktxserialization") 28 | include(":quickjs-converter-moshi") 29 | include(":samples:js-eval") 30 | include(":samples:repl") 31 | include(":samples:openai") 32 | include(":benchmark") 33 | --------------------------------------------------------------------------------